Shanraq.org Shanraq.org
Модули: отделить логику от запуска
IT

Rust: с нуля до своего органайзера Урок 44 из 50

Модули: отделить логику от запуска

Урок 44. Разделить код на файлы и открывать только нужные имена.

Текст переведён с помощью ИИ.

Предварительно: структуры, методы, органайзер. Начните с копии проекта: этот пример короткий и заменяет src/main.rs, чтобы увидеть границу доступа. Файловое сохранение задач ещё не началось.

Образ и опорная карта

В мастерской есть общий стол и закрытый шкаф с инструментами. На стол выставляют только то, что нужно посетителю; остальное остаётся внутри. Модуль (mod) группирует имена и задаёт границу видимости. pub открывает имя за этой границей. Образ ограничен: приватность в коде помогает строить понятный интерфейс, но не шифрует данные и не защищает компьютер от пользователя.

mainuse crate::organizer::Task → открытые Task::new и task.print → скрытые поля. crate обозначает корень текущей единицы компиляции. :: соединяет части пути к имени. use разрешает писать короткое Task вместо полного пути. pub struct Task открывает тип, но его поля id и title без pub остаются закрытыми. Поэтому main может вызвать открытый конструктор и метод, но не может написать task.title = .... Это даёт структуре возможность проверять изменения в своих методах. Self внутри impl Task означает сам тип Task, как в уроке 28.

Сначала один файл

Замените src/main.rs и выполните cargo run. Сообщения Cargo отделены от вывода программы. Новых зависимостей нет.

mod organizer {
    pub struct Task {
        id: u32,
        title: String,
    }
    impl Task {
        pub fn new(id: u32, title: &str) -> Self {
            Self {
                id,
                title: String::from(title),
            }
        }
        pub fn print(&self) {
            println!("Задача {}: {}", self.id, self.title);
        }
    }
}

use crate::organizer::Task;

fn main() {
    let task = Task::new(1, "Читать Rust");
    task.print();
}
Задача 1: Читать Rust

Затем два файла

Теперь перенесите всё внутри mod organizer { ... } в новый файл src/organizer.rs без внешних фигурных скобок. В начале src/main.rs вместо всего блока поставьте mod organizer;, оставьте use crate::organizer::Task; и fn main(). Точка с запятой после mod organizer сообщает Rust искать тело в отдельном файле. Команда cargo run должна вывести ту же строку. Если получите ошибку private field, вы пытаетесь обратиться к полю из main: используйте открытый метод. Если file not found, проверьте имя и место src/organizer.rs.

main.rs — корень исполняемой части Cargo-пакета, то есть программы, которую запускают. lib.rs может быть корнем отдельной библиотечной части того же пакета: её функции удобно вызывать из других программ и проверять отдельно. В этом упражнении lib.rs не нужен. Простая пара main.rs + organizer.rs уже отделяет запуск от логики. Для большой программы мы перенесём общую логику в библиотеку, когда научимся описывать её открытое поведение.

Вспомните без страницы

  1. Почему pub struct Task не открывает автоматически поле title?
  2. Что делает точка с запятой в mod organizer;?
  3. Чем отличается main.rs от lib.rs?

Задание

Обязательное. Добавьте открытый метод id(&self) -> u32 и выведите через него Номер: 1; поле id оставьте закрытым. Сделайте это и в варианте с двумя файлами. Проверьте cargo run. Не решайте задачу добавлением pub к самому полю.

Ответы

Показать ответы

Внутри impl Task метод может читать self.id; снаружи вызовите task.id(). При переносе в файл тело метода остаётся внутри src/organizer.rs.

Эталон после попытки

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

mod organizer {
    pub struct Task {
        id: u32,
        title: String,
    }
    impl Task {
        pub fn new(id: u32, title: &str) -> Self {
            Self {
                id,
                title: String::from(title),
            }
        }
        pub fn print(&self) {
            println!("Задача {}: {}", self.id, self.title);
        }
        pub fn id(&self) -> u32 {
            self.id
        }
    }
}

use crate::organizer::Task;

fn main() {
    let task = Task::new(1, "Читать Rust");
    task.print();
    println!("Номер: {}", task.id());
}
Задача 1: Читать Rust
Номер: 1

После проверки

Официальное объяснение модулей · разделение по файлам. Если impl ещё незнаком, вернитесь к уроку 28.

Предыдущий урок · Оглавление

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Комментарии (0)

Пока нет комментариев. Будьте первым.