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.