作用域
作用域是可以用该名称引用命名实体的源文本区域。以下部分提供了作用域规则和行为的详细信息,这些取决于实体的类型及其声明位置。名称如何解析为实体的过程在名称解析章节中描述。有关用于运行析构器的“丢弃作用域“的更多信息,请参阅析构器章节。
项作用域
直接在模块中声明的项的名称具有从模块开始到模块结束的作用域。这些项也是模块的成员,可以通过从其模块开始的路径引用。
作为语句声明的项的名称具有从项语句所在的块开始到块结束的作用域。
在同一模块或块中引入与另一个项同名的项是错误的。星号 glob 导入在处理重复名称和遮蔽方面具有特殊行为,有关更多详细信息,请参阅链接章节。
模块中的项可以遮蔽 prelude 中的项。
来自外部模块的项名称在嵌套模块中不在作用域内。可以使用路径引用另一个模块中的项。
关联项作用域
关联项没有作用域,只能通过使用从其关联的类型或 trait 开始的路径引用。方法也可以通过调用表达式引用。
类似于模块或块中的项,在 trait 或实现中引入与同一命名空间中 trait 或 impl 中的另一个项同名的项是错误的。
模式绑定作用域
局部变量模式绑定的作用域取决于其使用位置:
let语句绑定范围从let语句之后到其声明所在的块结束。
- 函数参数绑定在函数主体内。
- 闭包参数绑定在闭包主体内。
for绑定在循环主体内。
match守卫let绑定在后续守卫条件和 match 分支表达式中有效。
局部变量作用域不扩展到项声明中。
模式绑定遮蔽
模式绑定允许遮蔽作用域中的任何名称,但以下情况是错误的:
- Const 泛型参数
- 静态项
- 常量项
- 结构体 和 枚举的构造函数
以下示例说明了局部绑定如何遮蔽项声明:
#![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 约束]higher-ranked trait bounds 中声明。
'static 生命周期和占位生命周期 '_ 具有特殊含义,不能声明为参数。
生命周期泛型参数作用域
常量和静态项以及常量上下文只允许 'static 生命周期引用,因此其中不能有其他生命周期在作用域内。关联常量确实允许引用其 trait 或实现中声明的生命周期。
高阶 trait 约束作用域
作为[高阶 trait 约束]higher-ranked trait bound 声明的生命周期参数的作用域取决于其使用的场景。
- 作为 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
}
}
循环标签作用域
循环标签可以由循环表达式声明。循环标签的作用域从声明位置到循环表达式结束。作用域不扩展到项、闭包、异步块、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;
}
}
}
Prelude 作用域
Preludes 将实体带入每个模块的作用域。这些实体不是模块的成员,但在名称解析期间被隐式查询。
模块中的声明可以遮蔽 prelude 名称。
Prelude 是分层的,如果它们包含同名的实体,则一个会遮蔽另一个。Prelude 可能遮蔽其他 prelude 的顺序如下,其中较早的条目可能遮蔽较晚的条目:
macro_rules 作用域
macro_rules 宏的作用域在通过示例定义的宏章节中描述。该行为取决于 macro_use 和 macro_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
}
}
}