Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Разделение модулей на разные файлы

До сих пор все примеры в этой главе определяли несколько модулей в одном файле. Когда модули становятся большими, вы можете захотеть переместить их определения в отдельный файл, чтобы упростить навигацию по коду.

Например, начнём с кода из листинга 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.

Filename: src/lib.rs
mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}
Listing 7-21: Объявление модуля front_of_house, тело которого будет в src/front_of_house.rs

Далее поместите код, который был в фигурных скобках, в новый файл с именем src/front_of_house.rs, как показано в листинге 7-22. Компилятор знает, что нужно искать в этом файле, потому что он наткнулся на объявление модуля в корне крейта с именем front_of_house.

Filename: src/front_of_house.rs
pub mod hosting {
    pub fn add_to_waitlist() {}
}
Listing 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:

Filename: src/front_of_house.rs
pub mod hosting;

Затем мы создаём каталог src/front_of_house и файл hosting.rs для содержания определений, сделанных в модуле hosting:

Filename: 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 ищет в файле с тем же именем, что и модуль, код, который попадает в этот модуль.

Краткий итог

Rust позволяет разделить пакет на несколько крейтов, а крейт — на модули, чтобы вы могли ссылаться на элементы, определённые в одном модуле, из другого модуля. Вы можете сделать это, указав абсолютные или относительные пути. Эти пути могут быть приведены в область видимости с помощью оператора use, чтобы вы могли использовать более короткий путь для многократного использования элемента в этой области видимости. Код модуля по умолчанию является приватным, но вы можете сделать определения публичными, добавив ключевое слово pub.

В следующей главе мы рассмотрим некоторые структуры данных коллекций в стандартной библиотеке, которые вы можете использовать в своём аккуратно организованном коде.