作用域

作用域是源代码文本的区域,在该区域内,可以使用名称引用已命名的 实体。以下各节详细介绍了作用域规则和行为,这些规则和行为取决于实体的类型及其声明位置。名称如何解析为实体的过程在 名称解析 章节中进行了描述。有关用于运行析构函数的 “drop 作用域” 的更多信息,请参见 析构函数 章节。

条目作用域

直接在 模块 中声明的 条目 的名称的作用域从模块的开始扩展到模块的结束。这些条目也是模块的成员,可以使用从其模块开始的 路径 来引用。

声明为 语句 的条目的名称的作用域从条目语句所在的块的开始扩展到块的结束。

在同一模块或块中的同一 命名空间 内引入与另一个条目名称重复的条目是错误的。星号全局导入 对于处理重复名称和阴影具有特殊的行为,请参阅链接的章节以获取更多详细信息。模块中的条目可能会遮蔽 序幕 中的条目。

外部模块中的条目名称不在嵌套模块的作用域内。可以使用 路径 来引用另一个模块中的条目。

关联条目作用域

关联条目 没有作用域,只能通过使用从它们关联的类型或 trait 开始的 路径 来引用。方法 也可以通过 调用表达式 来引用。

与模块或块内的条目类似,在 trait 或实现中引入与同一命名空间中 trait 或 impl 中的另一个条目重复的条目是错误的。

模式绑定作用域

局部变量 模式 绑定的作用域取决于其使用位置

局部变量作用域不会扩展到条目声明中。

模式绑定遮蔽

模式绑定允许遮蔽作用域内的任何名称,但以下异常情况是错误的

以下示例说明了局部绑定如何遮蔽条目声明

#![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`
}
}

泛型参数作用域

泛型参数在 GenericParams 列表中声明。泛型参数的作用域在其声明的条目内。

所有参数都在泛型参数列表的作用域内,而与其声明顺序无关。以下是一些示例,其中参数可以在声明之前被引用

#![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>() {}
}

泛型参数也在类型边界和 where 子句的作用域内,例如

#![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>
{}
}

在函数内部声明的 条目 引用其外部作用域的泛型参数是错误的。

#![allow(unused)]
fn main() {
fn example<T>() {
    fn inner(x: T) {} // ERROR: can't use generic parameters from outer 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
}
}

生命周期作用域

生命周期参数在 GenericParams 列表和 高阶 trait 边界 中声明。

'static 生命周期和 占位符生命周期 '_ 具有特殊含义,不能声明为参数。

生命周期泛型参数作用域

常量静态 条目以及 const 上下文 仅允许 'static 生命周期引用,因此其中不能存在其他生命周期。关联常量 允许引用在其 trait 或实现中声明的生命周期。

高阶 trait 边界作用域

声明为 高阶 trait 边界 的生命周期参数的作用域取决于其使用的场景。

  • 作为 TypeBoundWhereClauseItem,声明的生命周期在类型和类型边界的作用域内。
  • 作为 TraitBound,声明的生命周期在边界类型路径的作用域内。
  • 作为 BareFunctionType,声明的生命周期在函数参数和返回类型的作用域内。
#![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 限制

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

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

循环标签作用域

循环标签 可以由 循环表达式 声明。循环标签的作用域从声明它的点到循环表达式的末尾。该作用域不扩展到 条目闭包async 代码块const 参数const 上下文 以及定义 for 循环 的迭代器表达式。

#![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.
}

}

循环标签可能会遮蔽外部作用域中同名的标签。对标签的引用指向最近的定义。

#![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;
    }
}
}

序幕作用域

序幕 将实体带入每个模块的作用域。实体不是模块的成员,而是在 名称解析 期间隐式查询。序幕名称可能会被模块中的声明遮蔽。

序幕是分层的,如果它们包含相同名称的实体,则一个序幕会遮蔽另一个序幕。序幕可能遮蔽其他序幕的顺序如下,其中较早的条目可能会遮蔽较晚的条目

  1. 外部序幕
  2. 工具序幕
  3. macro_use 序幕
  4. 标准库序幕
  5. 语言序幕

macro_rules 作用域

macro_rules 宏的作用域在 Macros By Example 章节中进行了描述。行为取决于 macro_usemacro_export 属性的使用。

派生宏辅助属性

派生宏辅助属性 在指定其对应 derive 属性 的条目中起作用。作用域从 derive 属性之后扩展到条目的末尾。辅助属性会遮蔽作用域中同名的其他属性。

Self 作用域

尽管 Self 是一个具有特殊含义的关键字,但它与名称解析的交互方式类似于普通名称。

结构体枚举联合体trait实现 的定义中,隐式的 Self 类型被视为类似于 泛型参数,并且作用域方式与泛型类型参数相同。

实现 的值 命名空间 中,隐式的 Self 构造函数在实现的主体(实现的 关联条目)中起作用。

#![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
    }
}
}