命名空间
一个 命名空间 是已声明 名称 的逻辑分组。名称根据其引用的实体种类被隔离到不同的命名空间中。命名空间允许一个命名空间中出现的名称与另一个命名空间中的相同名称不发生冲突。
存在几个不同的命名空间,每个命名空间包含不同种类的实体。名称的使用将根据上下文在不同的命名空间中寻找该名称的声明,如 名称解析 章节所述。
以下是命名空间列表及其对应的实体:
- 类型命名空间
- 值命名空间
- 宏命名空间
- 生命周期命名空间
- 标签命名空间
关于如何在不同命名空间中使用重叠名称而不会产生歧义的示例:
#![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 宏 是宏命名空间中具有相同名称的两个不同实体,但它们仍然可以在各自的上下文中使用。
注意
use导入仍然不能在模块或块中创建相同名称的重复绑定,无论子命名空间如何。#[macro_export] macro_rules! mymac { () => {}; } use myattr::mymac; // error[E0252]: 名称 `mymac` 被多次定义。