Разделение модулей на разные файлы
До сих пор все примеры в этой главе определяли несколько модулей в одном файле. Когда модули становятся большими, вы, возможно, захотите перенести их определения в отдельный файл, чтобы код был легче читать.
Например, давайте начнем с кода из Листинга 7-17, в котором были несколько модулей ресторана. Мы будем извлекать модули в файлы, вместо того чтобы все модули определялись в корневом файле крейта. В этом случае корневой файл крейта - это src/lib.rs
, но этот процесс также работает и с бинарными крейтами, у которых корневой файл - src/main.rs
.
Сначала мы извлечем модуль front_of_house
в отдельный файл. Удалите код внутри фигурных скобок для модуля front_of_house
, оставив только объявление mod front_of_house;
, чтобы src/lib.rs
содержал код, показанный в Листинге 7-21. Обратите внимание, что это не скомпилируется, пока мы не создадим файл src/front_of_house.rs
из Листинга 7-22.
Имя файла: src/lib.rs
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
Листинг 7-21: Объявление модуля front_of_house
, тело которого будет в src/front_of_house.rs
Далее, поместите код, который был внутри фигурных скобок, в новый файл с именем src/front_of_house.rs
, как показано в Листинге 7-22. Компилятор знает, что нужно смотреть в этот файл, потому что он столкнулся с объявлением модуля в корневом файле крейта с именем front_of_house
.
Имя файла: src/front_of_house.rs
pub mod hosting {
pub fn add_to_waitlist() {}
}
Листинг 7-22: Определения внутри модуля front_of_house
в src/front_of_house.rs
Обратите внимание, что вам нужно загружать файл с использованием объявления mod
только один раз в вашем дереве модулей. Как только компилятор знает, что файл является частью проекта (и знает, где в дереве модулей находится код, потому что вы указали mod
в определенном месте), другие файлы в вашем проекте должны ссылаться на загруженный файл с использованием пути к месту его объявления, как описано в разделе "Пути для обращения к элементу в дереве модулей". Другими словами, mod
не является операцией "включения", которую вы могли видеть в других языках программирования.
Далее, мы извлечем модуль hosting
в отдельный файл. Процесс немного отличается, потому что hosting
- это дочерний модуль front_of_house
, а не корневого модуля. Мы поместим файл для hosting
в новую директорию, которая будет именоваться по именам его предков в дереве модулей, в этом случае src/front_of_house.
Для начала перемещения hosting
, мы меняем src/front_of_house.rs
, чтобы он содержал только объявление модуля hosting
:
Имя файла: src/front_of_house.rs
pub mod hosting;
Затем мы создаем директорию src/front_of_house
и файл hosting.rs
, чтобы в него поместить определения, сделанные в модуле hosting
:
Имя файла: src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}
Если мы вместо этого поместим hosting.rs
в директорию src
, компилятор ожидает, что код из hosting.rs
будет в модуле hosting
, объявленном в корневом файле крейта, а не объявленном как дочерний модуль front_of_house
. Правила компилятора о том, какие файлы проверять для кода определенных модулей, означают, что директории и файлы должны более точно соответствовать дереву модулей.
Альтернативные пути файлов
До сих пор мы рассматривали наиболее распространенные пути файлов, которые использует компилятор Rust, но Rust также поддерживает более старый стиль путей файлов. Для модуля front_of_house
, объявленного в корневом файле крейта, компилятор будет искать код модуля в:
src/front_of_house.rs
(что мы рассматривали)
src/front_of_house/mod.rs
(старый стиль, все еще поддерживаемый путь)
Для модуля hosting
, который является подмодулем front_of_house
, компилятор будет искать код модуля в:
src/front_of_house/hosting.rs
(что мы рассматривали)
src/front_of_house/hosting/mod.rs
(старый стиль, все еще поддерживаемый путь)
Если вы используете оба стиля для одного и того же модуля, вы получите ошибку компиляции. Использование смеси обоих стилей для разных модулей в одном проекте допустимо, но может быть запутывающим для тех, кто будет изучать ваш проект.
Основной недостаток стиля, использующего файлы с именем mod.rs
, заключается в том, что в вашем проекте может получиться много файлов с именем mod.rs
, что может быть запутывающим, если вы открываете их одновременно в редакторе.
Мы перенесли код каждого модуля в отдельный файл, и дерево модулей осталось тем же. Функционные вызовы в eat_at_restaurant
будут работать без каких-либо изменений, даже если определения находятся в разных файлах. Эта техника позволяет вам перемещать модули в новые файлы по мере их роста.
Обратите внимание, что объявление pub use crate::front_of_house::hosting
в src/lib.rs
также не изменилось, и use
также не влияет на то, какие файлы компилируются как часть крейта. Ключевое слово mod
объявляет модули, и Rust ищет файл с тем же именем, что и модуль, для кода, который должен войти в этот модуль.