Розподіл модулів на різні файли

Поки що всі приклади в цій главі визначали декілька модулів у одному файлі. Коли модулі стають великими, ви можете захотіти перемістити їх визначення в окремі файли, щоб спростити навігацію по коду.

Наприклад, почнімо з коду із Лістинга 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 шукає в файлі з таким же ім'ям, що й у модуля, який входить у цей модуль.

Підсумок

Rust дозволяє розбити пакет на декілька крейтів, та крейт - на модулі, таким чином ви маєте змогу посилатися на елементи, визначенні в одному модулі, з іншого модуля. Це можна робити за допомогою вказання абсолютних чи відносних шляхів. Ці шляхи можна додати в область видимості оператором use, тому ми можете користуватися коротшими шляхами для багаторазового використання елементів у цій області видимості. Код модуля за замовчуванням є приватним, але можна зробити визначення загальнодоступними, додавши ключове слово pub.

У наступній главі ми подивимося деякі колекції структур данних із стандартної бібліотеки, які ви можете використовувати в своєму охайно організованому коді.