Skip to main content

使用use关键字将路径引入作用域

使用 use 关键字将路径引入作用域

在调用函数时必须写出路径可能会感到不方便和重复。在清单7-7中,无论我们选择绝对路径还是相对路径来调用add_to_waitlist函数,每次调用add_to_waitlist时我们都不得不指定front_of_househosting。幸运的是,有一种方法可以简化这个过程:我们可以使用use关键字创建一个路径的快捷方式,并在作用域中的其他地方使用更短的名称。

在清单7-11中,我们将crate::front_of_house::hosting模块引入了eat_at_restaurant函数的作用域,因此我们只需要指定hosting::add_to_waitlist来调用eat_at_restaurant中的add_to_waitlist函数。

文件名:src/lib.rs

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

清单7-11:使用use引入模块作用域

在根模块中加入use crate::front_of_house::hosting之前,外部代码必须通过restaurant::front_of_house::hosting::add_to_waitlist()来调用add_to_waitlist函数。现在,pub use重新导出了根模块中的hosting模块,外部代码可以使用restaurant::hosting::add_to_waitlist()来调用它。

重新导出在内部代码的结构与调用内部代码的程序员对于域的理解方式不同很有用。例如,在这个餐馆的类比中,经营餐馆的人会将餐馆分为“前厅”和“后厨”。但是,参观餐馆的顾客可能不会按这种方式来考虑餐厅的各个部分。使用pub use,我们可以在代码中使用一种结构,同时对外部使用者公开另一种结构。这样做可以使我们的库对于工作在库上的程序员和调用库的程序员都很清晰。在第14章的“使用pub use导出方便的公共API”部分,我们将再看一个pub use的例子,以及它如何影响你的crate的文档。

使用外部包

在第2章,我们编写了一个猜数字游戏项目,使用了一个名为rand的外部包来获取随机数。要在我们的项目中使用rand,我们需要在Cargo.toml文件中添加如下行:

文件名:Cargo.toml

rand = "0.8.5"

Cargo.toml中添加rand作为依赖项,告诉Cargo从crates.io下载rand包及其所有依赖项,并将rand提供给我们的项目。

然后,要将rand定义引入我们项目的作用域,我们需要使用use语句,并以crate的名称rand开头,然后列出要引入作用域的项。回顾一下第2章的“生成一个随机数”部分,我们引入了Rng trait,并调用了rand::thread_rng函数:

use rand::Rng;

fn main() {
let secret_number = rand::thread_rng().gen_range(1..=100);
}

Rust社区的成员已经在crates.io上提供了许多包,将它们引入到您的项目中需要遵循相同的步骤:在项目的Cargo.toml文件中列出它们,并使用use从它们的crate中引入项。

请注意,标准库std也是一个外部的crate。由于标准库是随Rust语言一起发布的,我们不需要更改Cargo.toml来包含std。但是,我们需要使用use来从标准库引入项到我们的项目作用域中。例如,要使用HashMap,我们将使用以下行:

use std::collections::HashMap;

这是一个以std(标准库crate的名称)开头的绝对路径。

使用嵌套路径来简化大型use列表

如果我们在同一个crate或同一个模块中使用了多个项,将每个项单独列在一行上会占用文件中很多的垂直空间。例如,在清单2-4的猜数字游戏中,以下两个use语句将项从std引入作用域:

文件名:src/main.rs

// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--

相反,我们可以使用嵌套路径在一行中将相同的项引入作用域。我们可以通过指定路径的共同部分,然后跟随两个冒号和花括号,包含不同的路径部分的列表来实现这一点

,如清单7-18所示。

文件名:src/main.rs

// --snip--
use std::{cmp::Ordering, io};
// --snip--

清单7-18:使用嵌套路径将具有相同前缀的多个项引入作用域

在更大的程序中,使用嵌套路径从相同的crate或模块中引入许多项可以大大减少所需的单独use语句数量!

在路径的任何级别上都可以使用嵌套路径,当合并两个共享子路径的use语句时,这非常有用。例如,清单7-19显示了两个use语句:一个将std::io引入作用域,另一个将std::io::Write引入作用域。

文件名:src/lib.rs

use std::io;
use std::io::Write;

清单7-19:两个use语句中一个是另一个的子路径

这两条路径的共同部分是std::io,并且这是第一条路径的完整部分。为了将这两条路径合并成一个use语句,我们可以在嵌套路径中使用self,如清单7-20所示。

文件名:src/lib.rs

use std::io::{self, Write};

清单7-20:将清单7-19中的路径合并为一个use语句

这一行将std::iostd::io::Write引入作用域。

通配符操作符

如果我们想要将一个路径中定义的所有公共项引入作用域,我们可以指定该路径,后跟*通配符操作符:

use std::collections::*;

这个use语句将std::collections中定义的所有公共项引入当前作用域。使用通配符操作符时要小心!通配符可能会使得很难分辨出哪些名称在作用域中以及您的程序中使用的名称是在哪里定义的。

通常在测试时使用通配符操作符来将所有内容都引入到tests模块中;我们将在第11章的“如何编写测试”部分中讨论这个问题。通配符操作符有时也被用作预导入模式的一部分:有关这种模式的更多信息,请参见标准库文档