Use 声明

语法:
Use声明 :
   use Use树 ;

Use树 :
      (简单路径? ::)? *
   | (简单路径? ::)? { (Use树 ( , Use树 )* ,?)? }
   | 简单路径 ( as ( 标识符 | _ ) )?

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 声明也可以存在于函数中
    use std::option::Option::{Some, None};

    // 相当于 '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 声明只在其所在的模块中可见。 如果在 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 Paths

注意: 本节内容不完整。

以下是一些关于 use 声明能够和不能够正常工作的例子:

#![allow(unused_imports)]
use std::path::{self, Path, PathBuf};  // good: std 是 crate 名称
use crate::foo::baz::foobaz;    // good: Foo 位于 crate 的根

mod foo {

    pub mod example {
        pub mod iter {}
    }

    use crate::foo::example::iter; // good: foo 位于 crate 的根
//  use example::iter;      // bad 在 2015 版次: 相对路径不允许没有 `self` ; 2018 版good
    use self::baz::foobaz;  // good: Self 引用模块 'foo'
    use crate::foo::bar::foobar;   // good: foo 位于 crate 的根

    pub mod bar {
        pub fn foobar() { }
    }

    pub mod baz {
        use super::bar::foobar; // good: Super 指的是模块 foo
        pub fn foobaz() { }
    }
}

fn main() {}

版次差异: 在 2015 版本中, use 路径还允许访问 crate 根中的条目。 使用上面的例子,以下 use 路径在 2015 版中可以使用但在 2018 版中无法使用:

mod foo {
    pub mod example { pub mod iter {} }
    pub mod baz { pub fn foobaz() {} }
}
use foo::example::iter;
use ::foo::baz::foobaz;
fn main() {}

2015 版不允许 use 声明引用 extern 预定义 。因此,在 2015 中,仍需要使用 extern crate 声明来引用 use 声明中的外部 crate。从 2018 版开始, use 声明可以像 extern crate 一样指定一个外部 crate 依赖。

在 2018 版本中,如果在作用域内存在与外部 crate 相同的名称,则使用该 crate 名称需要在前面加上 :: 以明确选择 crate 名称。这是为了保留与未来潜在更改的兼容性。

// use std::fs; // Error, 有歧义
use ::std::fs;  // 从 std crate 导入,而不是下面的模块。
use self::std::fs as self_fs;  // 导入下面的模块。

mod std {
    pub mod fs {}
}
fn main() {}

下划线导入

条目可以通过在路径前加一个下划线的形式 use path as _ 导入,而不必绑定到一个名字。 这种方法特别适用于导入 trait ,以便可以使用 trait 方法而不必导入该 trait 的符号,例如,如果该 trait 的符号可能与另一个符号发生冲突。 另一个例子是链接外部 crate ,也不导入其名称。

星号通配符将导入以不可命名的形式 _ 导入的条目。

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();
}

独特的、无法命名的符号是在宏展开后创建的,因而宏可以安全地创建 _ 导入的多个引用。例如,下面的代码将不会出错:

#![allow(unused)]
fn main() {
macro_rules! m {
    ($item: item) => { $item $item }
}

m!(use std as _;);
// 展开为:
// use std as _;
// use std as _;
}