Use声明
use-declarations.md
commit: eabdf09207bf3563ae96db9d576de0758c413d5d
本章译文最后维护日期:2021-1-24
句法:
UseDeclaration :
use
UseTree;
UseTree :
(SimplePath?::
)?*
| (SimplePath?::
)?{
(UseTree (,
UseTree )*,
?)?}
| SimplePath (as
( IDENTIFIER |_
) )?
use声明用来创建一个或多个与程序项路径同义的本地名称绑定。通常使用 use
声明来缩短引用模块所需的路径。这些声明可以出现在模块和块中,但通常在作用域顶部。
use声明支持多种便捷方法:
- 使用带有花括号的 glob-like(
::
) 句法use a::b::{c, d, e::f, g::h::i};
来同时绑定一个系列有共同前缀的路径。 - 使用关键字
self
,例如use a::b::{self, c, d::e};
,来同时绑定一系列有共同前缀和共同父模块的路径。 - 使用句法
use p::q::r as x;
将编译目标名称重新绑定为新的本地名称。这种也可以和上面两种方法一起使用:use a::b::{self as ab, c as abc}
。 - 使用星号通配符句法
use a::b::*;
来绑定与给定前缀匹配的所有路径。 - 将前面的方法嵌套重复使用,例如
use a::b::{self as ab, c, d::{*, e::f}};
。
use
声明的一个示例:
use std::option::Option::{Some, None};
use std::collections::hash_map::{self, HashMap};
fn foo<T>(_: T){}
fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){}
fn main() {
// 等价于 'foo(vec![std::option::Option::Some(1.0f64), std::option::Option::None]);'
foo(vec![Some(1.0f64), None]);
// `hash_map` 和 `HashMap` 在当前作用域内都有效.
let map1 = HashMap::new();
let map2 = hash_map::HashMap::new();
bar(map1, map2);
}
use
可见性
与其他程序项一样,默认情况下,use
声明对包含它的模块来说是私有的。同样的,如果使用关键字 pub
进行限定,use
声明也可以是公有的。use
声明可用于*重导出(re-expor)*名称。因此,公有的 use
声明可以将某些公有名称重定向到不同的目标定义中:甚至是位于不同模块内具有私有可见性的规范路径定义中。如果这样的重定向序列形成一个循环或不能明确地解析,则会导致编译期错误。
重导出的一个示例:
mod quux {
pub use self::foo::{bar, baz};
pub mod foo {
pub fn bar() {}
pub fn baz() {}
}
}
fn main() {
quux::bar();
quux::baz();
}
在本例中,模块 quux
重导出了在模块 foo
中定义的两个公共名称。
use
路径
注意:本章节内容还不完整。
一些正常和不正常的使用 use
程序项的例子:
:
版本差异: 在 2015 版中,
use
路径也允许访问 crate 根模块中的程序项。继续使用上面的例子,那以下use
路径的用法在 2015 版中有效,在 2018 版中就无效了:
2015 版不允许用 use声明来引用外部预导入包里的 crate。因此,在2015 版中仍然需要使用
extern crate
声明,以便在 use声明中去引用外部 crate。从 2018 版开始,use声明可以像extern crate
一样指定外部 crate 依赖关系。在 2018 版中,如果本地程序项与外部的 crate 名称相同,那么使用该 crate 名称需要一个前导的
::
来明确地选择该 crate 名称。这种做法是为了与未来可能发生的更改保持兼容。
下划线导入
通过使用形如为 use path as _
的带下划线的 use声明,可以在不绑定名称的情况下导入程序项。这对于导入一个 trait 特别有用,这样就可以在不导入 trait 的 symbol 的情况下使用这个 trait 的方法,例如,如果 trait 的 symbol 可能与另一个 symbol 冲突。再一个例子是链接外部的 crate 而不导入其名称。
使用星号全局导入(Asterisk glob imports,即 ::*
)句法将以 _
的形式导入能匹配到的所有程序项,但这些程序项在当前作用域中将处于不可命名的状态。
mod foo {
pub trait Zoo {
fn zoo(&self) {}
}
impl<T> Zoo for T {}
}
use self::foo::Zoo as _;
struct Zoo; // 下划线形式的导入就是为了避免和这个程序项在名字上起冲突
fn main() {
let z = Zoo;
z.zoo();
}
在宏扩展之后会创建一些惟一的、不可命名的 symbols,这样宏就可以安全地扩展出(emit)对 _
导入的多个引用。例如,下面代码不应该产生错误: