Dzielenie modułów na różne pliki
Do tej pory wszystkie przykłady w tym rozdziale definiowały wiele modułów w jednym pliku. Kiedy moduły stają się duże, możesz chcieć przenieść ich definicje do oddzielnego pliku, aby ułatwić nawigację po kodzie.
Na przykład, zacznijmy od kodu z Listing 7-17, który miał wiele modułów restauracji. Wyodrębnimy moduły do plików zamiast definiować wszystkie moduły w pliku głównym skrzynki. W tym przypadku plikiem głównym skrzynki jest src/lib.rs, ale ta procedura działa również w przypadku skrzynek binarnych, których plikiem głównym skrzynki jest src/main.rs.
Najpierw wyodrębnimy moduł front_of_house do jego własnego pliku. Usuń kod w nawiasach klamrowych dla modułu front_of_house, pozostawiając tylko deklarację mod front_of_house;, tak aby src/lib.rs zawierał kod pokazany w Listing 7-21. Zauważ, że to nie skompiluje się, dopóki nie utworzymy pliku src/front_of_house.rs w Listing 7-22.
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
Następnie umieść kod, który znajdował się w nawiasach klamrowych, w nowym pliku o nazwie src/front_of_house.rs, jak pokazano w Listing 7-22. Kompilator wie, aby szukać w tym pliku, ponieważ napotkał deklarację modułu w katalogu głównym skrzynki o nazwie front_of_house.
pub mod hosting {
pub fn add_to_waitlist() {}
}
Zauważ, że plik należy załadować za pomocą deklaracji mod tylko raz w drzewie modułów. Kiedy kompilator dowie się, że plik jest częścią projektu (i wie, gdzie w drzewie modułów znajduje się kod, ze względu na miejsce, w którym umieszczono instrukcję mod), inne pliki w projekcie powinny odwoływać się do kodu załadowanego pliku, używając ścieżki do miejsca, w którym został zadeklarowany, jak opisano w sekcji „Ścieżki do odwoływania się do elementu w drzewie modułów”. Innymi słowy, mod nie jest operacją „include”, którą mogłeś widzieć w innych językach programowania.
Następnie wyodrębnimy moduł hosting do jego własnego pliku. Proces jest nieco inny, ponieważ hosting jest modułem podrzędnym front_of_house, a nie modułu głównego. Plik dla hosting umieścimy w nowym katalogu, który będzie nazwany od jego przodków w drzewie modułów, w tym przypadku src/front_of_house.
Aby rozpocząć przenoszenie hosting, zmieniamy src/front_of_house.rs, tak aby zawierał tylko deklarację modułu hosting:
pub mod hosting;
Następnie tworzymy katalog src/front_of_house i plik hosting.rs, aby zawierać definicje z modułu hosting:
pub fn add_to_waitlist() {}
Gdybyśmy zamiast tego umieścili hosting.rs w katalogu src, kompilator oczekiwałby, że kod hosting.rs będzie w module hosting zadeklarowanym w katalogu głównym skrzynki, a nie zadeklarowanym jako dziecko modułu front_of_house. Zasady kompilatora dotyczące tego, które pliki sprawdzić pod kątem kodu poszczególnych modułów, oznaczają, że katalogi i pliki bardziej ściśle odpowiadają drzewu modułów.
Alternatywne ścieżki plików
Do tej pory omówiliśmy najbardziej idiomatyczne ścieżki plików używane przez kompilator Rust, ale Rust obsługuje również starszy styl ścieżek plików. Dla modułu o nazwie
front_of_housezadeklarowanego w katalogu głównym skrzynki, kompilator będzie szukał kodu modułu w:
- src/front_of_house.rs (to, co omówiliśmy)
- src/front_of_house/mod.rs (starszy styl, nadal obsługiwana ścieżka)
Dla modułu o nazwie
hosting, który jest podmodułemfront_of_house, kompilator będzie szukał kodu modułu w:
- src/front_of_house/hosting.rs (to, co omówiliśmy)
- src/front_of_house/hosting/mod.rs (starszy styl, nadal obsługiwana ścieżka)
Jeśli użyjesz obu stylów dla tego samego modułu, otrzymasz błąd kompilacji. Mieszanie obu stylów dla różnych modułów w tym samym projekcie jest dozwolone, ale może być mylące dla osób nawigujących po Twoim projekcie.
Główną wadą stylu, który używa plików o nazwie mod.rs, jest to, że projekt może zawierać wiele plików o nazwie mod.rs, co może prowadzić do zamieszania, gdy masz je otwarte w edytorze w tym samym czasie.
Przenieśliśmy kod każdego modułu do osobnego pliku, a drzewo modułów pozostało takie samo. Wywołania funkcji w eat_at_restaurant będą działać bez żadnych modyfikacji, mimo że definicje znajdują się w różnych plikach. Ta technika pozwala przenosić moduły do nowych plików, gdy rosną.
Zauważ, że instrukcja pub use crate::front_of_house::hosting w src/lib.rs również nie uległa zmianie, ani use nie ma wpływu na to, które pliki są kompilowane jako część skrzynki. Słowo kluczowe mod deklaruje moduły, a Rust szuka w pliku o tej samej nazwie co moduł kodu, który należy do tego modułu.
Podsumowanie
Rust pozwala dzielić pakiet na wiele skrzynek, a skrzynkę na moduły, tak aby można było odwoływać się do elementów zdefiniowanych w jednym module z innego modułu. Można to zrobić, określając ścieżki absolutne lub względne. Te ścieżki można wprowadzić do zasięgu za pomocą instrukcji use, aby można było używać krótszej ścieżki dla wielokrotnego użycia elementu w tym zasięgu. Kod modułu jest domyślnie prywatny, ale można uczynić definicje publicznymi, dodając słowo kluczowe pub.
W następnym rozdziale przyjrzymy się niektórym strukturom danych kolekcji w standardowej bibliotece, których można użyć w swoim schludnie zorganizowanym kodzie.