Use 声明
语法
UseDeclaration :
use
UseTree;
UseTree :
(SimplePath?::
)?*
| (SimplePath?::
)?{
(UseTree (,
UseTree )*,
?)?}
| SimplePath (as
( IDENTIFIER |_
) )?
一个 use 声明 创建一个或多个与某个其他 路径 同义的本地名称绑定。通常,use
声明用于缩短引用模块项所需的路径。这些声明可以出现在 模块 和 代码块 中,通常位于顶部。use
声明有时也称为 导入,或者,如果它是公共的,则称为 重新导出。
Use 声明支持许多方便的快捷方式
- 使用花括号语法
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::collections::hash_map::{self, HashMap}; fn foo<T>(_: T){} fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){} fn main() { // use declarations can also exist inside of functions use std::option::Option::{Some, None}; // Equivalent to 'foo(vec![std::option::Option::Some(1.0f64), // std::option::Option::None]);' foo(vec![Some(1.0f64), None]); // Both `hash_map` and `HashMap` are in scope. let map1 = HashMap::new(); let map2 = hash_map::HashMap::new(); bar(map1, map2); }
use
可见性
与项类似,use
声明默认情况下对其包含模块是私有的。同样,与项类似,如果使用 pub
关键字限定,则 use
声明可以是公共的。这样的 use
声明用于 重新导出 名称。因此,公共 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
项中允许的 路径 遵循 SimplePath 语法,并且类似于表达式中可能使用的路径。它们可以为以下项创建绑定:
它们不能导入 关联项、泛型参数、局部变量、带有 Self
的路径或 工具特性。下面描述了更多限制。
use
将为导入的实体的所有 命名空间 创建绑定,但 self
导入仅从类型命名空间导入(如下所述)除外。例如,以下说明了在两个命名空间中为同一名称创建绑定
#![allow(unused)] fn main() { mod stuff { pub struct Foo(pub i32); } // Imports the `Foo` type and the `Foo` constructor. use stuff::Foo; fn example() { let ctor = Foo; // Uses `Foo` from the value namespace. let x: Foo = ctor(123); // Uses `Foo` From the type namespace. } }
版本差异:在 2015 版本中,
use
路径相对于 crate 根目录。例如mod foo { pub mod example { pub mod iter {} } pub mod baz { pub fn foobaz() {} } } mod bar { // Resolves `foo` from the crate root. use foo::example::iter; // The `::` prefix explicitly resolves `foo` // from the crate root. use ::foo::baz::foobaz; } fn main() {}
2015 版本不允许使用声明引用 外部 prelude。因此,在 2015 年中,仍需要
extern crate
声明才能在use
声明中引用外部 crate。从 2018 版本开始,use
声明可以像extern crate
一样指定外部 crate 依赖项。
as
重命名
as
关键字可用于更改导入实体的名称。例如
#![allow(unused)] fn main() { // Creates a non-public alias `bar` for the function `foo`. use inner::foo as bar; mod inner { pub fn foo() {} } }
花括号语法
花括号可用于路径的最后一段,以从上一段导入多个实体,或者,如果没有上一段,则从当前作用域导入多个实体。花括号可以嵌套,从而创建路径树,其中每个段的分组在逻辑上与其父级组合以创建完整路径。
#![allow(unused)] fn main() { // Creates bindings to: // - `std::collections::BTreeSet` // - `std::collections::hash_map` // - `std::collections::hash_map::HashMap` use std::collections::{BTreeSet, hash_map::{self, HashMap}}; }
空花括号不导入任何内容,但会验证前导路径是否可访问。
版本差异:在 2015 版本中,路径相对于 crate 根目录,因此像
use {foo, bar};
这样的导入将从 crate 根目录导入名称foo
和bar
,而从 2018 年开始,这些名称相对于当前作用域。
self
导入
关键字 self
可以在 花括号语法 中使用,以在其自己的名称下创建父实体的绑定。
mod stuff { pub fn foo() {} pub fn bar() {} } mod example { // Creates a binding for `stuff` and `foo`. use crate::stuff::{self, foo}; pub fn baz() { foo(); stuff::bar(); } } fn main() {}
self
仅从父实体的 类型命名空间 创建绑定。例如,在以下代码中,仅导入了 foo
mod
mod bar { pub mod foo {} pub fn foo() {} } // This only imports the module `foo`. The function `foo` lives in // the value namespace and is not imported. use bar::foo::{self}; fn main() { foo(); //~ ERROR `foo` is a module }
注意:
self
也可以用作路径的第一段。self
作为第一段和在use
花括号内使用的逻辑是相同的;它表示父段的当前模块,或者如果没有父段,则表示当前模块。有关前导self
的含义的更多信息,请参见路径章节中的self
。
全局导入
*
字符可用作 use
路径的最后一段,以从前一段的实体导入所有可导入的实体。例如
#![allow(unused)] fn main() { // Creates a non-public alias to `bar`. use foo::*; mod foo { fn i_am_private() {} enum Example { V1, V2, } pub fn bar() { // Creates local aliases to `V1` and `V2` // of the `Example` enum. use Example::*; let x = V1; } } }
允许项和命名导入在同一 命名空间 中覆盖全局导入中的名称。也就是说,如果同一命名空间中的另一个项已经定义了一个名称,则全局导入将被覆盖。例如
#![allow(unused)] fn main() { // This creates a binding to the `clashing::Foo` tuple struct // constructor, but does not import its type because that would // conflict with the `Foo` struct defined here. // // Note that the order of definition here is unimportant. use clashing::*; struct Foo { field: f32, } fn do_stuff() { // Uses the constructor from `clashing::Foo`. let f1 = Foo(123); // The struct expression uses the type from // the `Foo` struct defined above. let f2 = Foo { field: 1.0 }; // `Bar` is also in scope due to the glob import. let z = Bar {}; } mod clashing { pub struct Foo(pub i32); pub struct Bar {} } }
*
不能用作第一段或中间段。
*
不能用于将模块的内容导入自身(例如 use self::*;
)。
版本差异:在 2015 版本中,路径相对于 crate 根目录,因此像
use *;
这样的导入是有效的,它表示从 crate 根目录导入所有内容。这不能在 crate 根目录本身中使用。
下划线导入
通过使用带有 use path as _
形式的下划线,可以导入项而不必绑定到名称。这对于导入 trait 特别有用,这样就可以使用其方法,而无需导入 trait 的符号,例如,如果 trait 的符号可能与另一个符号冲突。另一个示例是链接外部 crate 而无需导入其名称。
星号全局导入将导入以 _
导入的项的不可命名形式。
mod foo { pub trait Zoo { fn zoo(&self) {} } impl<T> Zoo for T {} } use self::foo::Zoo as _; struct Zoo; // Underscore import avoids name conflict with this item. fn main() { let z = Zoo; z.zoo(); }
在宏展开后创建唯一的,不可命名的符号,以便宏可以安全地发出对 _
导入的多个引用。例如,以下代码不应产生错误
#![allow(unused)] fn main() { macro_rules! m { ($item: item) => { $item $item } } m!(use std as _;); // This expands to: // use std as _; // use std as _; }
限制
以下是有效 use
声明的限制
use crate;
必须使用as
来定义绑定 crate 根目录的名称。
use {self};
是一个错误;使用self
时必须有一个前导段。
- 与任何项定义一样,
use
导入不能在模块或代码块中的同一命名空间中创建同一名称的重复绑定。
- 在
macro_rules
展开中不允许使用带有$crate
的use
路径。
use
路径不能通过 类型别名 引用枚举变体。例如#![allow(unused)] fn main() { enum MyEnum { MyVariant } type TypeAlias = MyEnum; use MyEnum::MyVariant; //~ OK use TypeAlias::MyVariant; //~ ERROR }
歧义
注意:本节不完整。
在 use
声明引用的名称存在歧义时,某些情况会出错。当存在两个不解析为同一实体的名称候选者时,会发生这种情况。
只要不使用名称,就允许全局导入在同一命名空间中导入冲突的名称。例如
mod foo { pub struct Qux; } mod bar { pub struct Qux; } use foo::*; use bar::*; //~ OK, no name conflict. fn main() { // This would be an error, due to the ambiguity. //let x = Qux; }
如果导入的是同一项(在重新导出之后),则允许多个全局导入导入同一名称,并且允许使用该名称。该名称的可见性是导入的最大可见性。例如
mod foo { pub struct Qux; } mod bar { pub use super::foo::Qux; } // These both import the same `Qux`. The visibility of `Qux` // is `pub` because that is the maximum visibility between // these two `use` declarations. pub use bar::*; use foo::*; fn main() { let _: Qux = Qux; }