命名空间
命名空间是对已声明的名称进行逻辑分组。名称根据其指代的实体的类型被隔离到不同的命名空间中。命名空间允许一个命名空间中出现的名称不与另一个命名空间中的相同名称冲突。
存在几种不同的命名空间,每种命名空间包含不同类型的实体。名称的使用将根据上下文,在不同的命名空间中查找该名称的声明,正如在名称解析章节中所描述的那样。
以下是命名空间的列表,以及它们对应的实体
- 类型命名空间
- 模块声明
- 外部 crate 声明
- 外部 crate 预导入项
- 结构体、联合体、枚举、枚举变体声明
- Trait 条目声明
- 类型别名
- 关联类型声明
- 内置类型:布尔值、数值和文本
- 泛型类型参数
Self
类型- 工具属性模块
- 值命名空间
- 宏命名空间
- 生命周期命名空间
- 标签命名空间
一个关于如何在不同命名空间中重叠的名称可以被明确使用的例子
#![allow(unused)] fn main() { // Foo introduces a type in the type namespace and a constructor in the value // namespace. struct Foo(u32); // The `Foo` macro is declared in the macro namespace. macro_rules! Foo { () => {}; } // `Foo` in the `f` parameter type refers to `Foo` in the type namespace. // `'Foo` introduces a new lifetime in the lifetime namespace. fn example<'Foo>(f: Foo) { // `Foo` refers to the `Foo` constructor in the value namespace. let ctor = Foo; // `Foo` refers to the `Foo` macro in the macro namespace. Foo!{} // `'Foo` introduces a label in the label namespace. 'Foo: loop { // `'Foo` refers to the `'Foo` lifetime parameter, and `Foo` // refers to the type namespace. let x: &'Foo Foo; // `'Foo` refers to the label. break 'Foo; } } }
没有命名空间的命名实体
以下实体具有显式名称,但这些名称不属于任何特定的命名空间。
字段
即使结构体、枚举和联合体的字段被命名,这些命名的字段也不存在于显式的命名空间中。它们只能通过字段表达式访问,该表达式仅检查被访问的特定类型的字段名称。
Use 声明
use
声明具有它导入到作用域中的命名别名,但 use
项本身不属于特定的命名空间。相反,它可以根据导入的条目类型,将别名引入到多个命名空间中。
子命名空间
宏命名空间被分为两个子命名空间:一个用于感叹号风格的宏,另一个用于属性。当解析属性时,作用域内的任何感叹号风格的宏都将被忽略。反之,解析感叹号风格的宏将忽略作用域内的属性宏。这防止了一种风格遮蔽另一种风格。
例如,cfg
属性和 cfg
宏是宏命名空间中两个同名的不同实体,但它们仍然可以在各自的上下文中使用。
即使它们的子命名空间不同,use
导入遮蔽另一个宏仍然是一个错误。