Scopes
A scope is the region of source text where a named entity may be referenced with that name. The following sections provide details on the scoping rules and behavior, which depend on the kind of entity and where it is declared. The process of how names are resolved to entities is described in the name resolution chapter. More information on “drop scopes” used for the purpose of running destructors may be found in the destructors chapter.
Item scopes
The name of an item declared directly in a module has a scope that extends from the start of the module to the end of the module. These items are also members of the module and can be referred to with a path leading from their module.
The name of an item declared as a statement has a scope that extends from the start of the block the item statement is in until the end of the block.
It is an error to introduce an item with a duplicate name of another item in the same namespace within the same module or block. Asterisk glob imports have special behavior for dealing with duplicate names and shadowing, see the linked chapter for more details. Items in a module may shadow items in a prelude.
Item names from outer modules are not in scope within a nested module. A path may be used to refer to an item in another module.
Associated item scopes
Associated items are not scoped and can only be referred to by using a path leading from the type or trait they are associated with. Methods can also be referred to via call expressions.
Similar to items within a module or block, it is an error to introduce an item within a trait or implementation that is a duplicate of another item in the trait or impl in the same namespace.
Pattern binding scopes
The scope of a local variable pattern binding depends on where it is used:
let
statement bindings range from just after thelet
statement until the end of the block where it is declared.- Function parameter bindings are within the body of the function.
- Closure parameter bindings are within the closure body.
for
andwhile let
bindings are within the loop body.if let
bindings are within the consequent block.match
arms bindings are within the match guard and the match arm expression.
Local variable scopes do not extend into item declarations.
Pattern binding shadowing
Pattern bindings are allowed to shadow any name in scope with the following exceptions which are an error:
- Const generic parameters
- Static items
- Const items
- Constructors for structs and enums
The following example illustrates how local bindings can shadow item declarations:
#![allow(unused)] fn main() { fn shadow_example() { // Since there are no local variables in scope yet, this resolves to the function. foo(); // prints `function` let foo = || println!("closure"); fn foo() { println!("function"); } // This resolves to the local closure since it shadows the item. foo(); // prints `closure` } }
Generic parameter scopes
Generic parameters are declared in a GenericParams list. The scope of a generic parameter is within the item it is declared on.
All parameters are in scope within the generic parameter list regardless of the order they are declared. The following shows some examples where a parameter may be referenced before it is declared:
#![allow(unused)] fn main() { // The 'b bound is referenced before it is declared. fn params_scope<'a: 'b, 'b>() {} trait SomeTrait<const Z: usize> {} // The const N is referenced in the trait bound before it is declared. fn f<T: SomeTrait<N>, const N: usize>() {} }
Generic parameters are also in scope for type bounds and where clauses, for example:
#![allow(unused)] fn main() { trait SomeTrait<'a, T> {} // The <'a, U> for `SomeTrait` refer to the 'a and U parameters of `bounds_scope`. fn bounds_scope<'a, T: SomeTrait<'a, U>, U>() {} fn where_scope<'a, T, U>() where T: SomeTrait<'a, U> {} }
It is an error for items declared inside a function to refer to a generic parameter from their outer scope.
#![allow(unused)] fn main() { fn example<T>() { fn inner(x: T) {} // ERROR: can't use generic parameters from outer function } }
Generic parameter shadowing
It is an error to shadow a generic parameter with the exception that items declared within functions are allowed to shadow generic parameter names from the function.
#![allow(unused)] fn main() { fn example<'a, T, const N: usize>() { // Items within functions are allowed to shadow generic parameter in scope. 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>() {} // ERROR: 'a is already in use fn example_type<T>() {} // ERROR: T is already in use fn example_const<const N: usize>() {} // ERROR: N is already in use fn example_mixed<const T: usize>() {} // ERROR: T is already in use } }
Lifetime scopes
Lifetime parameters are declared in a GenericParams list and higher-ranked trait bounds.
The 'static
lifetime and placeholder lifetime '_
have a special meaning and cannot be declared as a parameter.
Lifetime generic parameter scopes
Constant and static items and const contexts only ever allow 'static
lifetime references, so no other lifetime may be in scope within them.
Associated consts do allow referring to lifetimes declared in their trait or implementation.
Higher-ranked trait bound scopes
The scope of a lifetime parameter declared as a higher-ranked trait bound depends on the scenario where it is used.
- As a TypeBoundWhereClauseItem the declared lifetimes are in scope in the type and the type bounds.
- As a TraitBound the declared lifetimes are in scope within the bound type path.
- As a BareFunctionType the declared lifetimes are in scope within the function parameters and return type.
#![allow(unused)] fn main() { trait Trait<'a>{} fn where_clause<T>() // 'a is in scope in both the type and the type bounds. where for <'a> &'a T: Trait<'a> {} fn bound<T>() // 'a is in scope within the bound. where T: for <'a> Trait<'a> {} struct Example<'a> { field: &'a u32 } // 'a is in scope in both the parameters and return type. type FnExample = for<'a> fn(x: Example<'a>) -> Example<'a>; }
Impl trait restrictions
Impl trait types can only reference lifetimes declared on a function or implementation.
#![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 {} // The `impl Trait2` here is not allowed to refer to 'b but it is allowed to // refer to 'a. fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a> + use<'a>> { // ... Example } }
Loop label scopes
Loop labels may be declared by a loop expression.
The scope of a loop label is from the point it is declared till the end of the loop expression.
The scope does not extend into items, closures, async blocks, const arguments, const contexts, and the iterator expression of the defining for
loop.
#![allow(unused)] fn main() { 'a: for n in 0..3 { if n % 2 == 0 { break 'a; } fn inner() { // Using 'a here would be an error. // break 'a; } } // The label is in scope for the expression of `while` loops. 'a: while break 'a {} // Loop does not run. 'a: while let _ = break 'a {} // Loop does not run. // The label is not in scope in the defining `for` loop: 'a: for outer in 0..5 { // This will break the outer loop, skipping the inner loop and stopping // the outer loop. 'a: for inner in { break 'a; 0..1 } { println!("{}", inner); // This does not run. } println!("{}", outer); // This does not run, either. } }
Loop labels may shadow labels of the same name in outer scopes. References to a label refer to the closest definition.
#![allow(unused)] fn main() { // Loop label shadowing example. 'a: for outer in 0..5 { 'a: for inner in 0..5 { // This terminates the inner loop, but the outer loop continues to run. break 'a; } } }
Prelude scopes
Preludes bring entities into scope of every module. The entities are not members of the module, but are implicitly queried during name resolution. The prelude names may be shadowed by declarations in a module.
The preludes are layered such that one shadows another if they contain entities of the same name. The order that preludes may shadow other preludes is the following where earlier entries may shadow later ones:
macro_rules
scopes
The scope of macro_rules
macros is described in the Macros By Example chapter.
The behavior depends on the use of the macro_use
and macro_export
attributes.
Derive macro helper attributes
Derive macro helper attributes are in scope in the item where their corresponding derive
attribute is specified.
The scope extends from just after the derive
attribute to the end of the item.
Helper attributes shadow other attributes of the same name in scope.
Self
scope
Although Self
is a keyword with special meaning, it interacts with name resolution in a way similar to normal names.
The implicit Self
type in the definition of a struct, enum, union, trait, or implementation is treated similarly to a generic parameter, and is in scope in the same way as a generic type parameter.
The implicit Self
constructor in the value namespace of an implementation is in scope within the body of the implementation (the implementation’s associated items).
#![allow(unused)] fn main() { // Self type within struct definition. struct Recursive { f1: Option<Box<Self>> } // Self type within generic parameters. struct SelfGeneric<T: Into<Self>>(T); // Self value constructor within an implementation. struct ImplExample(); impl ImplExample { fn example() -> Self { // Self type Self() // Self value constructor } } }