В практической ситуации модуль переместили глубже в иерархии: как выбор между путями crate:: и super:: влияет на устойчивость ссылок на элементы?
Путь с префиксом crate:: разрешается от корня текущего crate, поэтому перемещение исходного модуля обычно не меняет смысл такой ссылки. Путь с super:: разрешается относительно родительского модуля, поэтому после перемещения он может начать указывать на другой элемент или перестать компилироваться.
Модульная система Rust должна одновременно поддерживать иерархическую организацию кода и предсказуемое разрешение имён. Для этого язык различает абсолютные пути внутри crate и пути, зависящие от положения текущего модуля.
Такое разделение решает практическую проблему связанности кода с расположением файлов и модулей. Код может явно выразить, должен ли элемент находиться относительно корня crate или рядом с текущим модулем.
Относительный путь удобен для локальных связей: дочерний модуль может обратиться к элементу родителя через super::. Однако при перемещении модуля меняется его родитель, и та же запись может разрешаться иначе.
Если ссылка логически относится к публичной структуре всего crate, использование super:: создаёт лишнюю зависимость от расположения модуля. Если же ссылка намеренно должна следовать за родителем, замена на crate:: может нарушить модульную архитектуру и скрыть ошибочное обращение к элементу вне ожидаемой области.
crate:: начинает поиск от корня текущего crate. Он не зависит от количества промежуточных родительских модулей, поэтому ссылка сохраняется при переносе текущего модуля в другую ветвь иерархии, если целевой путь от корня не изменился.
super:: начинает поиск в непосредственном родительском модуле. Два одинаковых текста с super:: в разных местах могут обозначать разные элементы, поскольку их родительские модули различаются. Несколько уровней можно поднять повторением super::, но такой путь ещё сильнее зависит от глубины вложенности.
self:: обозначает текущий модуль, а обычный относительный путь обычно разрешается в контексте текущей области имён с учётом правил разрешения Rust. Для устойчивых ссылок на crate-wide элементы обычно выбирают crate::; для тесно связанной внутренней структуры — super:: или self::.
В примере обе функции сейчас находят одну константу. После перемещения nested в другую ветвь crate::config::LIMIT останется корректным, если config не перемещён, а путь через super::super:: потребует повторной проверки и, возможно, изменения.
Это не означает, что crate:: обходится без ограничений. Целевой элемент всё равно должен существовать по указанному пути и быть доступным с точки зрения приватности; абсолютность пути не отменяет правила видимости.
В библиотеке есть модуль transport, внутри которого первоначально размещён модуль http. Код http обращается к общему типу конфигурации через цепочку super::super::config, потому что конфигурация находится выше в дереве.
Возможны два решения. Сохранить super::super::config просто и подчёркивает связь с текущим родителем, но любое изменение вложенности потребует правок. Перейти на crate::config немного явнее и связывает код с корнем crate, зато перенос http между ветвями не меняет путь к общей конфигурации.
Для общего типа конфигурации выбирается crate::config: зависимость является глобальной для crate, а не локальной для конкретного родителя. В результате реорганизация модулей не вызывает каскад исправлений относительных путей, тогда как локальные элементы, принадлежащие непосредственному родителю, по-прежнему разумно адресовать через super::.
crate:: доступность приватного элемента?Нет. crate:: задаёт только начальную точку разрешения пути — корень crate. Затем Rust всё равно проверяет существование каждого сегмента и правила приватности. Поэтому абсолютный путь к приватному элементу другого модуля не превращает его в публичный.
super::?Нет. Если после переноса у модуля случайно сохраняется такой же подходящий родительский путь и нужный элемент доступен из нового родителя, код может продолжить компилироваться. Но семантическая устойчивость не гарантируется: путь зависит от новой позиции и может начать ссылаться на другой элемент с тем же именем.
super:: на путь через crate:: без изменения дизайна?Не всегда. Замена корректна только при наличии целевого элемента по пути от корня и подходящей видимости. Кроме того, она может расширить концептуальную область зависимости: код, который должен работать только внутри родительского модуля, начнёт явно зависеть от структуры всего crate, что ухудшит локальность и сопровождаемость.