|
|
## 使用use将路径纳入范围
|
|
|
|
|
|
使用use关键字创建路径,使**范围内**其他地方可以使用更短的名称。
|
|
|
|
|
|
![image-20230112091925053](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112091925053.png)
|
|
|
|
|
|
使用 use 和路径在作用域中类似于文件系统中创建一个符号链接。 通过在 crate 根中添加 use crate::front_of_house::hosting,hosting 现在是该作用域中有效的名称,就像 hosting 模块已在 crate 根中定义一样。 使用的路径也会检查隐私,就像其他路径一样。
|
|
|
|
|
|
**use 只在特定作用域中创建了快捷方式。**将 eat_at_restaurant 函数移动到新的子模块 customer 中,然后它是不同的作用域,因此函数体将不能编译。
|
|
|
|
|
|
![image-20230112093658359](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112093658359.png)
|
|
|
|
|
|
该警告表示该 use 在其作用域中不再使用! 要解决此问题,请将 use 移动到 customer 模块中,或在 child customer 模块中使用 super::hosting 引用父模块中的快捷方式。
|
|
|
|
|
|
![image-20230112093820390](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112093820390.png)
|
|
|
|
|
|
|
|
|
|
|
|
在使用引入结构、枚举和其他项时`use`,惯用的做法是指定完整路径。
|
|
|
|
|
|
![image-20230112100654208](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112100654208.png)
|
|
|
|
|
|
|
|
|
|
|
|
### 处理相同名称问题
|
|
|
|
|
|
不用as:
|
|
|
|
|
|
```rust
|
|
|
use std::fmt;
|
|
|
use std::io;
|
|
|
|
|
|
fn function1() -> fmt::Result {
|
|
|
// --snip--
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
fn function2() -> io::Result<()> {
|
|
|
// --snip--
|
|
|
Ok(())
|
|
|
}
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
使用as处理相同名称
|
|
|
|
|
|
![image-20230112103459332](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112103459332.png)
|
|
|
|
|
|
### pub use (未实践,有点迷茫)
|
|
|
|
|
|
当我们使用 use 关键字将名称带入作用域时,新作用域中可用的名称是**私有**的。 为了使调用我们代码的代码能够像在其作用域中定义了该名称一样引用该名称,我们可以结合 pub 和 use。 此技术称为**重新导出**,因为我们正在将项目带入作用域,并使该项目可供其他人带入其作用域。
|
|
|
|
|
|
`pub use`语句主要用于控制您的crate的公共接口,通过重新导出某些项目并使它们更易于访问crate的用户。这可以使API更方便和用户友好,因为**它减少了访问某些项目所需的嵌套层数**,并允许用户以与crate的内部结构不同的方式思考领域。
|
|
|
|
|
|
- `use` 关键字是将某个路径中的名称引入当前作用域,使之在当前作用域内直接可用。
|
|
|
- `pub use` 关键字是将某个路径中的名称引入当前作用域并且标记为公共,使之在当前作用域外也可用。
|
|
|
|
|
|
![image-20230112145135795](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112145135795.png)
|
|
|
|
|
|
在此更改之前,外部代码调用该函数 `restaurant::front_of_house::hosting::add_to_waitlist()`。现在`pub use`已经从根模块中重新导出了`hosting`模块,外部代码现在可以改用该路径`restaurant::hosting::add_to_waitlist()`。
|
|
|
|
|
|
|
|
|
|
|
|
### 使用外部包
|
|
|
|
|
|
同第二章猜谜游戏。
|
|
|
|
|
|
1. 在Cargo.toml 文件内添加 dependencies、
|
|
|
|
|
|
![image-20230112150952802](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112150952802.png)
|
|
|
|
|
|
2. 将`Rng`特征带入作用域并调用`rand::thread_rng`函数:
|
|
|
|
|
|
![image-20230112151307961](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112151307961.png)
|
|
|
|
|
|
[cartes.io](https://crates.io/)
|
|
|
|
|
|
|
|
|
|
|
|
请注意,标准`std`库也是我们包外部的一个板条箱。因为标准库是随 Rust 语言一起提供的,所以我们不需要更改*Cargo.toml*来包含`std`。但是我们确实需要引用它`use`以将项目从那里带入我们的包范围。例如,`HashMap`我们将使用这一行:
|
|
|
|
|
|
```rust
|
|
|
#![allow(unused)]
|
|
|
fn main() {
|
|
|
use std::collections::HashMap;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 解决相同crate重复use问题
|
|
|
|
|
|
```rust
|
|
|
// --snip--
|
|
|
use std::cmp::Ordering;
|
|
|
use std::io;
|
|
|
// --snip--
|
|
|
```
|
|
|
|
|
|
修改为:
|
|
|
|
|
|
```rust
|
|
|
// --snip--
|
|
|
use std::{cmp::Ordering, io};
|
|
|
// --snip--
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
当两个use一个为另一个子路径时
|
|
|
|
|
|
```rust
|
|
|
use std::io;
|
|
|
use std::io::Write;
|
|
|
```
|
|
|
|
|
|
可写成:
|
|
|
|
|
|
```rust
|
|
|
use std::io::{self, Write};
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### *操作符
|
|
|
|
|
|
如果我们想要将路径中定义的所有公共项目都带入作用域中,我们可以指定该路径,然后跟着 * 通配符:
|
|
|
|
|
|
```rust
|
|
|
#![allow(unused)]
|
|
|
fn main() {
|
|
|
use std::collections::*;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
该`use`语句将 中定义的所有公共项目`std::collections`带入当前范围。使用 glob 运算符时要小心!Glob 可以让你更难分辨哪些名字在范围内,以及在你的程序中使用的名字是在哪里定义的。
|
|
|
|
|
|
测试时经常使用 glob 运算符,将所有被测试的东西都带入`tests`模块;
|
|
|
|
|
|
|
|
|
|
|
|
## 拆分mod为不同文件
|
|
|
|
|
|
注意,**您只需要在模块树中使用 mod 声明加载一次文件**。一旦编译器知道文件是项目的一部分(并且因为您放置 mod 语句的位置而知道代码在模块树中的位置),项目中的其他文件应该使用声明中的路径来引用**已加载文件的代码**,如“在模块树中引用项目的路径”部分所述。换句话说,mod 不是其他编程语言中可能看到的“include”操作(在每个文件中都需要使用 include 来引入头文件。)。
|
|
|
|
|
|
接下来,我们将提取托管模块到其自己的文件中。这个过程有点不同,因为托管是 front_of_house 的子模块,而不是根模块。我们将托管文件放在一个新目录中,该目录将命名为其模块树中祖先的名称,在这种情况下为 src/front_of_house/。
|
|
|
|
|
|
![image-20230112162129076](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112162129076.png)
|
|
|
|
|
|
|
|
|
|
|
|
接着拆分hosting
|
|
|
|
|
|
![image-20230112170412078](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230112170412078.png)
|
|
|
|
|
|
|
|
|
|
|
|
### 备用文件路径
|
|
|
|
|
|
到目前为止,我们已经介绍了 Rust 编译器使用的最标准文件路径,但 Rust 还支持一种旧式文件路径。对于在 crate 根目录中声明的名为 front_of_house 的模块,编译器将在以下位置查找模块的代码:
|
|
|
|
|
|
- src/front_of_house.rs(我们讨论过的)
|
|
|
- src/front_of_house/mod.rs(旧式,仍然支持的路径)
|
|
|
|
|
|
对于名为 hosting 的 front_of_house 的子模块,编译器将在以下位置查找模块的代码:
|
|
|
|
|
|
- src/front_of_house/hosting.rs(我们讨论过的)
|
|
|
- src/front_of_house/hosting/mod.rs(旧式,仍然支持的路径)
|
|
|
|
|
|
|
|
|
|
|
|
**如果您对同一模块使用了两种样式,则会得到编译错误**。在同一项目中为不同模块使用混合样式是允许的,但可能会使人们在您的项目中导航时感到困惑。
|
|
|
|
|
|
使用名为 mod.rs 的文件的样式的主要缺点是,您的项目可能会有许多名为 mod.rs 的文件,在您的编辑器中同时打开它们时可能会感到困惑。
|
|
|
|
|
|
|
|
|
|
|
|
将模块代码移动到单独的文件中, 并保持模块树不变. 这样做可以让代码更容易维护和扩展, 当模块变得越来越大时可以将它们移动到新的文件中。
|
|
|
|
|
|
pub use crate::front_of_house::hosting 语句在src/lib.rs中, 表示将 crate::front_of_house::hosting 模块暴露在crate根作用域下, 其他模块可以直接使用hosting模块中的函数.
|
|
|
|
|
|
use 关键字并不影响编译器编译文件, 它只是让编译器知道这个模块在哪里, 以便在编译时能够找到这个模块. mod关键字声明了模块,并且Rust会在与模块同名的文件中查找该模块的代码.
|
|
|
|
|
|
## 总结
|
|
|
|
|
|
Rust 允许您将一个包拆分成多个 crates 和一个 crate 拆分成模块,以便您可以从一个模块引用另一个模块中定义的项目。您可以通过指定绝对或相对路径来实现这一点。可以使用 use 语句将这些路径带入作用域,以便在该作用域中多次使用项目时使用较短的路径。默认情况下,模块代码是私有的,但您可以通过添加 pub 关键字来使定义公共。 |