ПрограммированиеBackend разработчик

Как в Rust реализована работа с модификаторами видимости (pub, pub(crate), pub(super)) и чем они отличаются от модификаторов в других языках? Какие проблемы могут возникнуть при неправильной настройке видимости элементов модуля?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В Rust модификаторы видимости управляют доступом к элементам модулей (структурам, функциям, константам и т.д.). По умолчанию всё, что объявляется в модуле, является приватным (доступно только в данном модуле). Существуют специальные модификаторы:

  • pub: делает элемент общедоступным (видимым из любых внешних модулей).
  • pub(crate): видимость ограничена текущим crate (пакетом).
  • pub(super): видимость ограничена родительским модулем.
  • pub(in path): видимость ограничена определённым путём.

Пример:

mod foo { pub struct Bar { pub x: i32, // поле доступно везде y: i32, // поле приватно } pub(crate) fn crate_fn() {} pub(super) fn super_fn() {} fn private_fn() {} }

Главное отличие от, например, C++ или Java — нет отдельного уровня для protected, и доступность жестко контролируется на уровне модулей/путей, а не иерархии классов.

Вопрос с подвохом.

Вопрос: Если структура объявлена как pub struct Foo, будут ли её приватные поля доступны в другом модуле того же проекта?

Часто отвечают: Да, ведь структура публичная.

Правильный ответ: Нет, только сама структура (Foo) станет видимой, а её поля — только если поля также объявлены с модификатором pub. Поля без pub остаются приватными, даже если сама структура публичная.

Пример:

mod foo { pub struct Bar { pub x: i32, y: i32, } } fn main() { let bar = foo::Bar { x: 1, y: 2 }; // Ошибка: поле `y` недоступно }

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В крупном проекте публично экспортировали структуру через pub, но поля сделали приватными по умолчанию. Другие модули не могли создавать экземпляры структуры напрямую, и единственным решением оказалось написание дополнительных конструкторов или объявление нужных полей как pub. Это вызвало отказ API до окончательной доработки.


История

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


История

В одном из плагинов к серверу API были использованы pub(super) для структур, но спустя время возникла необходимость доступа к ним из других модулей; из-за настройки видимости пришлось в ряде мест кардинально переписывать модули, чтобы обеспечить нужную область видимости без нарушения инкапсуляции.