Jak dołączyć moduł z innego pliku z tego samego projektu?


131

Postępując zgodnie z tym przewodnikiem stworzyłem projekt Cargo.

src/main.rs

fn main() {
    hello::print_hello();
}

mod hello {
    pub fn print_hello() {
        println!("Hello, world!");
    }
}

z których korzystam

cargo build && cargo run

i kompiluje się bez błędów. Teraz próbuję podzielić główny moduł na dwie części, ale nie mogę dowiedzieć się, jak dołączyć moduł z innego pliku.

Moje drzewo projektów wygląda tak

├── src
    ├── hello.rs
    └── main.rs

oraz zawartość plików:

src/main.rs

use hello;

fn main() {
    hello::print_hello();
}

src/hello.rs

mod hello {
    pub fn print_hello() {
        println!("Hello, world!");
    }
}

Kiedy kompiluję to cargo build, otrzymuję

error[E0432]: unresolved import `hello`
 --> src/main.rs:1:5
  |
1 | use hello;
  |     ^^^^^ no `hello` external crate

Próbowałem postępować zgodnie z sugestiami kompilatora i zmodyfikowałem main.rsdo:

#![feature(globs)]

extern crate hello;

use hello::*;

fn main() {
    hello::print_hello();
}

Ale to nadal niewiele pomaga, teraz rozumiem:

error[E0463]: can't find crate for `hello`
 --> src/main.rs:3:1
  |
3 | extern crate hello;
  | ^^^^^^^^^^^^^^^^^^^ can't find crate

Czy istnieje trywialny przykład, jak dołączyć jeden moduł z bieżącego projektu do głównego pliku projektu?



Odpowiedzi:


239

Nie potrzebujesz mod hellow swoim hello.rspliku. Kod w dowolnym pliku oprócz katalogu głównego skrzynki ( main.rsdla plików wykonywalnych, lib.rsdla bibliotek) jest automatycznie przydzielany do przestrzeni nazw w module.

Aby dołączyć kod z hello.rsdo swojego main.rs, użyj mod hello;. Jest rozwijany do kodu, który jest w hello.rs(dokładnie tak, jak miałeś wcześniej). Twoja struktura plików jest taka sama, a kod wymaga niewielkiej zmiany:

main.rs:

mod hello;

fn main() {
    hello::print_hello();
}

hello.rs:

pub fn print_hello() {
    println!("Hello, world!");
}

1
Późne pytanie, czy nie zadziałałoby również, gdybym określił to za pomocą use hello zamiast mod hello?
Christian Schmitt,

17
@ChristianSchmitt Nie, to różne rzeczy. usejest po prostu przestrzenią nazw, podczas gdy modściąga plik. Możesz usena przykład użyć , aby móc wywołać print_hellofunkcję bez konieczności poprzedzania przestrzenią nazw
Renato Zannon

27

Jeśli chcesz mieć zagnieżdżone moduły ...

Rdza 2018

Nie jest już wymagane posiadanie pliku mod.rs(chociaż nadal jest obsługiwany). Idiomatyczną alternatywą jest nazwanie pliku nazwą modułu:

$ tree src
src
├── main.rs
├── my
│   ├── inaccessible.rs
│   └── nested.rs
└── my.rs

main.rs

mod my;

fn main() {
    my::function();
}

my.rs

pub mod nested; // if you need to include other modules

pub fn function() {
    println!("called `my::function()`");
}

Rdza 2015

Musisz umieścić mod.rsplik w swoim folderze o tej samej nazwie co twój moduł. Rust by Example wyjaśnia to lepiej.

$ tree src
src
├── main.rs
└── my
    ├── inaccessible.rs
    ├── mod.rs
    └── nested.rs

main.rs

mod my;

fn main() {
    my::function();
}

mod.rs

pub mod nested; // if you need to include other modules

pub fn function() {
    println!("called `my::function()`");
}

5
Załóżmy, że chcę użyć coś z inaccessible.rsw nested.rs... w jaki sposób to zrobić?
Heman Gandhi

Aby uzyskać dostęp do siostrzanego pliku .rs z pliku innego niż main.rs, użyj atrybutu path. Tak więc u góry pliku nested.rs dodaj następujący tekst: #[path = "inaccessible.rs"]a w następnym wierszu:mod inaccessible;
Ogrodnik

@Gandhi Zobacz atrybut ścieżki
ogrodnik

2
@HemanGandhi dodaj mod inaccessible;do, my/mod.rsaby uczynić go podmodułem z my, a następnie uzyskaj dostęp do modułu rodzeństwa za nested.rspomocą ścieżki względnej super::inaccessible::function(). nie potrzebujesz pathtutaj atrybutu.
artin

10

Bardzo podoba mi się odpowiedź Gardenera. Korzystałem z sugestii dla moich deklaracji modułów. Niech ktoś zadzwoni, jeśli jest z tym problem techniczny.

./src
├── main.rs
├── other_utils
│   └── other_thing.rs
└── utils
    └── thing.rs

main.rs

#[path = "utils/thing.rs"] mod thing;
#[path = "other_utils/other_thing.rs"] mod other_thing;

fn main() {
  thing::foo();
  other_thing::bar();
}

utils / thing.rs

pub fn foo() {
  println!("foo");
}

other_utils / other_thing.rs

#[path = "../utils/thing.rs"] mod thing;

pub fn bar() {
  println!("bar");
  thing::foo();
}

Musiałem użyć tej „sztuczki”, aby ponownie wyeksportować fnpod taką samą nazwą, jak plik, w którym się znajdował.#[path = "./add_offer.rs"] mod _add_offer; pub use self::_add_offer::add_offer;
Arek Bal

1
to powinna być zaakceptowana odpowiedź imo
Homam Bahrani
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.