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?

zdrowaśka
źródło
1
możliwy duplikat podstawowego importu Rusta (obejmuje)
Levans,

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!");
}
Renato Zannon
źródło
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()`");
}
amxa
źródło
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();
}
rodo
źródło
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