Области видимости
Область видимости — это область исходного текста, где на именованную сущность можно ссылаться по этому имени. Следующие разделы предоставляют подробности о правилах и поведении областей видимости, которые зависят от вида сущности и места её объявления. Процесс того, как имена разрешаются в сущности, описан в главе о разрешении имён. Дополнительная информация об “областях сброса”, используемых для запуска деструкторов, может быть найдена в главе о деструкторах.
Области видимости элементов
Имя элемента, объявленного непосредственно в модуле, имеет область видимости, которая простирается от начала модуля до конца модуля. Эти элементы также являются членами модуля и на них можно ссылаться с помощью пути, ведущего из их модуля.
Имя элемента, объявленного как оператор, имеет область видимости, которая простирается от начала блока, в котором находится оператор элемента, до конца блока.
Ошибкой является введение элемента с дублирующим именем другого элемента в том же пространстве имён в пределах того же модуля или блока. Звёздочные глобальные импорты имеют особое поведение для работы с дублирующими именами и затенением, см. связанную главу для подробностей.
Элементы в модуле могут затенять элементы в прелюдии.
Имена элементов из внешних модулей не находятся в области видимости внутри вложенного модуля. Путь может быть использован для ссылки на элемент в другом модуле.
Области видимости ассоциированных элементов
Ассоциированные элементы не имеют области видимости и на них можно ссылаться только с помощью пути, ведущего от типа или трейта, с которым они ассоциированы. Методы также могут быть вызваны через выражения вызова.
Подобно элементам внутри модуля или блока, ошибкой является введение элемента внутри трейта или реализации, который дублирует другой элемент в трейте или реализации в том же пространстве имён.
Области видимости привязок образцов
Область видимости привязки образца локальной переменной зависит от того, где она используется:
- Привязки оператора
letдействуют от момента сразу после оператораletдо конца блока, где она объявлена.
- Привязки параметров функции находятся в теле функции.
- Привязки параметров замыкания находятся в теле замыкания.
- Привязки
forнаходятся в теле цикла.
- Привязки веток
matchнаходятся в ограничителе match и выражении ветки match.
Области видимости локальных переменных не распространяются на объявления элементов.
Затенение привязок образцов
Привязкам образцов разрешено затенять любое имя в области видимости со следующими исключениями, которые являются ошибкой:
- Обобщённые параметры констант
- Статические элементы
- Константные элементы
- Конструкторы для структур и перечислений
Следующий пример иллюстрирует, как локальные привязки могут затенять объявления элементов:
#![allow(unused)] fn main() { fn shadow_example() { // Поскольку локальных переменных в области видимости ещё нет, это разрешается в функцию. foo(); // печатает `function` let foo = || println!("closure"); fn foo() { println!("function"); } // Это разрешается в локальное замыкание, поскольку оно затеняет элемент. foo(); // печатает `closure` } }
Области видимости обобщённых параметров
Обобщённые параметры объявляются в списке GenericParams. Область видимости обобщённого параметра находится в пределах элемента, на котором он объявлен.
Все параметры находятся в области видимости внутри списка обобщённых параметров независимо от порядка их объявления. Следующее показывает некоторые примеры, где на параметр можно ссылаться до его объявления:
#![allow(unused)] fn main() { // Ограничение 'b упоминается до его объявления. fn params_scope<'a: 'b, 'b>() {} trait SomeTrait<const Z: usize> {} // Константа N упоминается в ограничении трейта до её объявления. fn f<T: SomeTrait<N>, const N: usize>() {} }
Обобщённые параметры также находятся в области видимости для ограничений типов и where-предложений, например:
#![allow(unused)] fn main() { trait SomeTrait<'a, T> {} // <'a, U> для `SomeTrait` ссылаются на параметры 'a и U функции `bounds_scope`. fn bounds_scope<'a, T: SomeTrait<'a, U>, U>() {} fn where_scope<'a, T, U>() where T: SomeTrait<'a, U> {} }
Ошибкой является ссылка элементов, объявленных внутри функции, на обобщённый параметр из их внешней области видимости.
#![allow(unused)] fn main() { fn example<T>() { fn inner(x: T) {} // ОШИБКА: нельзя использовать обобщённые параметры из внешней функции } }
Затенение обобщённых параметров
Ошибкой является затенение обобщённого параметра, за исключением того, что элементам, объявленным внутри функций, разрешено затенять имена обобщённых параметров из функции.
#![allow(unused)] fn main() { fn example<'a, T, const N: usize>() { // Элементам внутри функций разрешено затенять обобщённые параметры в области видимости. fn inner_lifetime<'a>() {} // OK fn inner_type<T>() {} // OK fn inner_const<const N: usize>() {} // OK } }
#![allow(unused)] fn main() { trait SomeTrait<'a, T, const N: usize> { fn example_lifetime<'a>() {} // ОШИБКА: 'a уже используется fn example_type<T>() {} // ОШИБКА: T уже используется fn example_const<const N: usize>() {} // ОШИБКА: N уже используется fn example_mixed<const T: usize>() {} // ОШИБКА: T уже используется } }
Области видимости времён жизни
Параметры времени жизни объявляются в списке GenericParams и ограничениях трейтов высшего ранга.
Время жизни 'static и заполнитель времени жизни '_ имеют специальное значение и не могут быть объявлены как параметры.
Области видимости параметров времени жизни
Константные и статические элементы и константные контексты всегда допускают только ссылки с временем жизни 'static, поэтому никакое другое время жизни не может находиться в области видимости внутри них.
Ассоциированные константы допускают ссылки на времена жизни, объявленные в их трейте или реализации.
Области видимости ограничений трейтов высшего ранга
Область видимости параметра времени жизни, объявленного как ограничение трейта высшего ранга, зависит от сценария, где он используется.
- Как TypeBoundWhereClauseItem объявленные времена жизни находятся в области видимости в типе и ограничениях типов.
- Как TraitBound объявленные времена жизни находятся в области видимости в пути типа ограничения.
- Как BareFunctionType объявленные времена жизни находятся в области видимости в параметрах функции и возвращаемом типе.
#![allow(unused)] fn main() { trait Trait<'a>{} fn where_clause<T>() // 'a находится в области видимости как в типе, так и в ограничениях типов. where for <'a> &'a T: Trait<'a> {} fn bound<T>() // 'a находится в области видимости внутри ограничения. where T: for <'a> Trait<'a> {} struct Example<'a> { field: &'a u32 } // 'a находится в области видимости как в параметрах, так и в возвращаемом типе. type FnExample = for<'a> fn(x: Example<'a>) -> Example<'a>; }
Ограничения Impl trait
Типы Impl trait могут ссылаться только на времена жизни, объявленные в функции или реализации.
#![allow(unused)] fn main() { trait Trait1 { type Item; } trait Trait2<'a> {} struct Example; impl Trait1 for Example { type Item = Element; } struct Element; impl<'a> Trait2<'a> for Element {} // `impl Trait2` здесь не может ссылаться на 'b, но может // ссылаться на 'a. fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a> + use<'a>> { // ... Example } }
Области видимости меток циклов
Метки циклов могут быть объявлены выражением цикла.
Область видимости метки цикла простирается от точки её объявления до конца выражения цикла.
Область видимости не распространяется на элементы, замыкания, асинхронные блоки, константные аргументы, константные контексты и выражение итератора определяющего цикла for.
#![allow(unused)] fn main() { 'a: for n in 0..3 { if n % 2 == 0 { break 'a; } fn inner() { // Использование 'a здесь было бы ошибкой. // break 'a; } } // Метка находится в области видимости для выражения циклов `while`. 'a: while break 'a {} // Цикл не выполняется. 'a: while let _ = break 'a {} // Цикл не выполняется. // Метка не находится в области видимости в определяющем цикле `for`: 'a: for outer in 0..5 { // Это прервёт внешний цикл, пропустив внутренний цикл и остановив // внешний цикл. 'a: for inner in { break 'a; 0..1 } { println!("{}", inner); // Это не выполняется. } println!("{}", outer); // Это тоже не выполняется. } }
Метки циклов могут затенять метки с тем же именем во внешних областях видимости. Ссылки на метку относятся к ближайшему определению.
#![allow(unused)] fn main() { // Пример затенения метки цикла. 'a: for outer in 0..5 { 'a: for inner in 0..5 { // Это завершает внутренний цикл, но внешний цикл продолжает выполняться. break 'a; } } }
Области видимости прелюдий
Прелюдии вводят сущности в область видимости каждого модуля. Сущности не являются членами модуля, но неявно запрашиваются во время разрешения имён.
Имена прелюдий могут быть затенены объявлениями в модуле.
Прелюдии наслаиваются таким образом, что одна затеняет другую, если они содержат сущности с одинаковым именем. Порядок, в котором прелюдии могут затенять другие прелюдии, следующий, где более ранние записи могут затенять более поздние:
- Внешняя прелюдия
- Инструментальная прелюдия
- Прелюдия
macro_use - Прелюдия стандартной библиотеки
- Языковая прелюдия
Области видимости macro_rules
Область видимости макросов macro_rules описана в главе Макросы по примеру.
Поведение зависит от использования атрибутов macro_use и macro_export.
Вспомогательные атрибуты derive-макросов
Вспомогательные атрибуты derive-макросов находятся в области видимости в элементе, где указан их соответствующий атрибут derive.
Область видимости простирается от момента сразу после атрибута derive до конца элемента.
Вспомогательные атрибуты затеняют другие атрибуты с тем же именем в области видимости.
Область видимости Self
Хотя Self является ключевым словом со специальным значением, оно взаимодействует с разрешением имён способом, похожим на обычные имена.
Неявный тип Self в определении структуры, перечисления, объединения, трейта или реализации обрабатывается аналогично обобщённому параметру и находится в области видимости так же, как обобщённый параметр типа.
Неявный конструктор Self в пространстве имён значений реализации находится в области видимости в теле реализации (в ассоциированных элементах реализации).
#![allow(unused)] fn main() { // Тип Self в определении структуры. struct Recursive { f1: Option<Box<Self>> } // Тип Self в обобщённых параметрах. struct SelfGeneric<T: Into<Self>>(T); // Конструктор значения Self в реализации. struct ImplExample(); impl ImplExample { fn example() -> Self { // Тип Self Self() // Конструктор значения Self } } }