Исторически Rust с самого начала проектировался как язык для написания масштабируемых, надёжных системных программ. Система модулей была создана для строгого разграничения пространств имён, изоляции кода и организации больших проектов без конфликтов имён. Модули позволяют структурировать код, скрывать детали реализации и управлять публичным API.
Проблема заключается в том, что при росте проекта возникает вопрос изоляции компонентов, совместного использования кода и управления видимостью. Ошибки часто связаны с неправильным использованием ключевых слов pub, pub(crate), а также с отсутствием или неверной организацией структуры каталогов и файлов.
Решение: в Rust модуль объявляется с помощью ключевого слова mod; файлы и каталоги структуируют пространство имён, подчёркивая иерархию. Всё приватно по умолчанию, а ключевые слова pub, pub(crate), pub(super) позволяют управлять видимостью. Корректное использование экспортов, alias-ов, а также грамотное разбиение проекта на модули делают код масштабируемым, поддерживаемым и безопасным.
Пример кода:
// src/lib.rs mod network; pub use network::client::Client; // src/network/mod.rs pub mod client; // src/network/client.rs pub struct Client { pub name: String, }
Ключевые особенности:
Если структура каталога не совпадает с определениями модулей, что произойдёт?
Код не скомпилируется: Rust ожидает строгое соответствие файлов и модулей (например, если объявлен mod foo, то должен существовать файл foo.rs или директория foo/mod.rs).
Может ли pub(crate) использоваться для скрытия реализации от внешних потребителей, но быть доступным всем модулям внутри крейта?
Да, pub(crate) делает элемент видимым в любом модуле того же крейта, но невидимым для внешних проектов, использующих этот крейт как зависимость.
Как импортировать функции из глубоко вложенного модуля в корневой файл без публичной реэкспортации (pub use)?
Через прямую ссылку по иерархии: crate::module::submodule::function. Без pub use они будут доступны только внутри крейта.
В проекте модуль сети содержит все компоненты сервера, клиента, парсера протоколов в одном файле network.rs. Всё объявлено pub, для тестирования подключен напрямую внутренний код. Со временем растёт ненужная связанность и становится сложно отделить публичный интерфейс от реализации.
Плюсы:
Минусы:
Network разбит на submodules: client, server, protocol. Только публичные интерфейсы экспортируются из network, API компактный, детали инкапсулированы. Тесты для каждого модуля изолированы.
Плюсы:
Минусы: