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

Визначення модулів для керування областю видимості та приватністю (Defining Modules to Control Scope and Privacy)

У цьому розділі ми поговоримо про модулі та інші частини системи модулів, а саме шляхи (paths), які дають змогу називати елементи; ключове слово use, яке вводить шлях (path) в область видимості; і ключове слово pub, щоб робити елементи публічними. Ми також обговоримо ключове слово as, зовнішні пакети та glob-оператор.

Шпаргалка з модулів

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

  • Починайте з кореня крейту: Під час компіляції крейта компілятор спочатку шукає в файлі кореня крейту (зазвичай src/lib.rs для бібліотечного крейта і src/main.rs для бінарного крейта) код для компіляції.
  • Оголошення модулів: У файлі кореня крейта ви можете оголошувати нові модулі; скажімо, ви оголошуєте модуль “garden” за допомогою mod garden;. Компілятор шукатиме код модуля в таких місцях:
    • Вбудовано, всередині фігурних дужок, які замінюють крапку з комою після mod garden
    • У файлі src/garden.rs
    • У файлі src/garden/mod.rs
  • Оголошення підмодулів: У будь-якому файлі, окрім кореня крейту, ви можете оголошувати підмодулі. Наприклад, ви можете оголосити mod vegetables; у src/garden.rs. Компілятор шукатиме код підмодуля всередині каталогу, названого на честь батьківського модуля, у таких місцях:
    • Вбудовано, безпосередньо після mod vegetables, у фігурних дужках замість крапки з комою
    • У файлі src/garden/vegetables.rs
    • У файлі src/garden/vegetables/mod.rs
  • Шляхи (paths) до коду в модулях: Після того як модуль став частиною вашого крейта, ви можете посилатися на код у цьому модулі з будь-якого іншого місця в тому самому крейті, якщо правила приватності це дозволяють, використовуючи шлях (path) до коду. Наприклад, тип Asparagus у модулі garden vegetables буде знайдено за адресою crate::garden::vegetables::Asparagus.
  • Приватне проти публічного: Код у межах модуля за замовчуванням є приватним для його батьківських модулів. Щоб зробити модуль публічним, оголосіть його з pub mod замість mod. Щоб зробити елементи всередині публічного модуля також публічними, використовуйте pub перед їхніми оголошеннями.
  • Ключове слово use: В межах області видимості ключове слово use створює скорочення для елементів, щоб зменшити повторення довгих шляхів (paths). У будь-якій області видимості, яка може посилатися на crate::garden::vegetables::Asparagus, ви можете створити скорочення за допомогою use crate::garden::vegetables::Asparagus;, і відтоді вам потрібно буде лише писати Asparagus, щоб використовувати цей тип у цій області видимості.

Тут ми створюємо бінарний крейт з назвою backyard, який ілюструє ці правила. Каталог крейта, який також називається backyard, містить такі файли та каталоги:

backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │   └── vegetables.rs
    ├── garden.rs
    └── main.rs

Файл кореня крейта в цьому випадку — src/main.rs, і він містить:

use crate::garden::vegetables::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!("I'm growing {plant:?}!");
}

Рядок pub mod garden; каже компілятору включити код, який він знаходить у src/garden.rs, а саме:

pub mod vegetables;

Тут pub mod vegetables; означає, що код у src/garden/vegetables.rs також включається. Цей код такий:

#[derive(Debug)]
pub struct Asparagus {}

Тепер давайте перейдемо до деталей цих правил і продемонструємо їх у дії!

Групування пов’язаного коду в модулях

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

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

У ресторанній індустрії деякі частини ресторану називають front of house, а інші — back of house. Front of house — це місце, де перебувають клієнти; це охоплює те, де хости саджають клієнтів, офіціанти приймають замовлення та оплату, а бармени готують напої. Back of house — це місце, де шеф-кухарі та кухарі працюють на кухні, посудомийники прибирають, а менеджери виконують адміністративну роботу.

Щоб структурувати наш крейт у такий спосіб, ми можемо організувати його функції у вкладені модулі. Створіть новий бібліотечний крейт під назвою restaurant, виконавши cargo new restaurant --lib. Потім внесіть код з Лістингу 7-1 у src/lib.rs, щоб визначити деякі модулі та сигнатури функцій; цей код є розділом front of house.

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

Ми визначаємо модуль за допомогою ключового слова mod, після якого йде назва модуля (у цьому випадку front_of_house). Тіло модуля потім розміщується всередині фігурних дужок. Усередині модулів ми можемо розміщувати інші модулі, як у цьому випадку з модулями hosting і serving. Модулі також можуть містити оголошення інших елементів, таких як структури, перелічення, константи, трейти і, як у Лістингу 7-1, функції.

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

Раніше ми згадували, що src/main.rs і src/lib.rs називаються коренями крейту. Причина їхньої назви в тому, що вміст будь-якого з цих двох файлів утворює модуль із назвою crate у корені модульної структури крейта, відомої як дерево модулів.

Лістинг 7-2 показує дерево модулів для структури в Лістингу 7-1.

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

Це дерево показує, як деякі модулі вкладені в інші модулі; наприклад, hosting вкладений у front_of_house. Дерево також показує, що деякі модулі є сусідніми, тобто вони визначені в одному модулі; hosting і serving є сусідніми, визначеними всередині front_of_house. Якщо модуль A міститься всередині модуля B, ми кажемо, що модуль A є дочірнім модулю B, а модуль B є батьківським модулю A. Зверніть увагу, що все дерево модулів має корінь під неявним модулем із назвою crate.

Дерево модулів може нагадати вам дерево каталогів файлової системи на вашому комп’ютері; це дуже влучне порівняння! Так само як каталоги у файловій системі, ви використовуєте модулі для організації свого коду. І так само як файли в каталозі, нам потрібен спосіб знаходити наші модулі.