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 – это не операция «include», которую вы могли видеть в других языках программирования.

Далее мы вынесем модуль 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.

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