命名空间
命名空间是已声明名称的逻辑分组。名称根据其引用的实体类型被隔离到不同的命名空间中。命名空间允许一个命名空间中的名称出现不会与另一个命名空间中的相同名称冲突。
存在多个不同的命名空间,每个命名空间包含不同类型的实体。名称的使用将根据上下文在不同的命名空间中查找该名称的声明,如名称解析章节所述。
以下是命名空间及其对应实体的列表:
- 类型命名空间
- 值命名空间
- 宏命名空间
- 生命周期命名空间
- 标签命名空间
一个示例,展示不同命名空间中重叠的名称如何可以被无歧义地使用:
#![allow(unused)]
fn main() {
// Foo 在类型命名空间中引入一个类型,在值命名空间中引入一个构造函数。
struct Foo(u32);
// `Foo` 宏声明在宏命名空间中。
macro_rules! Foo {
() => {};
}
// `f` 参数类型中的 `Foo` 引用类型命名空间中的 `Foo`。
// `'Foo` 在生命周期命名空间中引入一个新的生命周期。
fn example<'Foo>(f: Foo) {
// `Foo` 引用值命名空间中的 `Foo` 构造函数。
let ctor = Foo;
// `Foo` 引用宏命名空间中的 `Foo` 宏。
Foo!{}
// `'Foo` 在标签命名空间中引入一个标签。
'Foo: loop {
// `'Foo` 引用 `'Foo` 生命周期参数,`Foo`
// 引用类型命名空间。
let x: &'Foo Foo;
// `'Foo` 引用标签。
break 'Foo;
}
}
}
没有命名空间的命名实体
以下实体具有显式名称,但这些名称不属于任何特定的命名空间。
字段
尽管结构体、枚举和联合体字段是有名称的,但这些命名字段不存在于显式的命名空间中。它们只能通过字段表达式访问,该表达式仅检查所访问特定类型的字段名称。
Use 声明
use 声明具有它导入作用域的命名别名,但 use 项本身不属于特定命名空间。相反,它可以根据导入的项类型将别名引入多个命名空间。
子命名空间
宏命名空间分为两个子命名空间:一个用于叹号风格宏,一个用于属性。解析属性时,作用域中的任何叹号风格宏将被忽略。反之,解析叹号风格宏时,将忽略作用域中的属性宏。这防止了一种风格遮蔽另一种风格。
例如,cfg 属性和 cfg 宏是宏命名空间中两个具有相同名称的不同实体,但它们仍可在各自的上下文中使用。
Note
use导入仍不能在模块或块中创建相同名称的重复绑定,无论子命名空间如何。#[macro_export] macro_rules! mymac { () => {}; } use myattr::mymac; // error[E0252]: 名称 `mymac` 被多次定义。