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:

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:

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>> {
    // ...
   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:

  1. Extern prelude
  2. Tool prelude
  3. macro_use prelude
  4. Standard library prelude
  5. Language prelude

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
    }
}
}