随着我们的坑越来越多,越来越大,我们必须要对各种坑进行管理了。Rust为我们提供了一套坑务管理系统,方便大家有条不紊的寻找、管理、填埋自己的各种坑。

Rust提供给我们一些管理代码的特性:

  • Packages:Cargo的一个特性,帮助你进行构建、测试和共享crates
  • Crates:生成库或可执行文件的模块树
  • Modulesuse:用于控制代码组织、范围和隐私路径
  • Paths:struct、function和module的命名方法

下面我们来具体看一下这些特性是如何帮助我们组织代码的。

Packages和Crates

package可以理解为一个项目,而crate可以理解为一个代码库。crate可以供多个项目使用。那我们的项目中package和crate是怎么定义的呢?

之前我们总是通过IDEA来新建项目,今天我们换个方法,在命令行中使用cargo命令来创建。

$ cargo new hello-world      Created binary (application) `hello-world` package $ ls hello-world Cargo.toml src $ ls hello-world/src main.rs

可以看到,我们使用cargo创建项目后,只有两个文件,Cargo.toml和src目录下的main.rs。

Cargo.toml是管理项目依赖的文件,每个Cargo.toml定义一个package。main.rs文件的存在表示package中包含一个二进制crate,它是二进制crate的入口文件,crate的名称和package相同。如果src目录下存在lib.rs文件,说明package中包含一个和package名称相同的库crate。

一个package可以包含多个二进制crate,它们由src/lib目录下的文件定义。如果你的项目想引用他人的crate,可以在Cargo.toml文件中增加依赖。每个crate都有自己的命名空间,因此如果你引入了一个crate里面定义了一个名为hello的函数,你仍然可以在自己的crate中再定义一个名为hello的函数。

Module

Module帮助我们在crate中组织代码,同时Module也是封装代码的重要工具。接下来还是通过一个栗子来详细了解Module。

前面我们说过,库crate定义在src/lib.rs文件中。这里首先创建一个包含了库crate的package:

cargo new --lib restaurant

然后在src中定义一些module和函数。

mod front_of_house {     mod hosting {         fn add_to_waitlist() {}          fn seat_at_table() {}     }      mod serving {         fn take_order() {}          fn serve_order() {}          fn take_payment() {}     } }

可以看到我们使用关键字mod来定义Module,Module中可以继续定义Module或函数。这样我们就可以比较方便的把相关的函数放到一个Module中,并为Module命名,提高代码的可读性。另外Module中还可以定义struct和枚举。由于Module中可以嵌套定义子Module,最终我们定义出来的代码类似一个树形。

那么如何访问Module中的函数呢?这就要提到Path了。这部分比较好理解,Module树相当于系统文件目录,而Path则是目录的路径。

Path

这里的路径和系统文件路径一样,都分为相对路径和绝对路径两种。其中绝对路径必须以crate开头,因为它代码整个Module树的根节点。路径之间使用的是双冒号来表示引用。

现在我来尝试在一个函数中调用add_to_waitlist函数:

05-1

可以看到这里不管用绝对路径还是相对路径都报错了,错误信息是模块hosting和函数add_to_waitlist是私有(private)的。我们先暂时放下这个错误,根据这里的错误提示,我们知道了当我们定义一个module时,默认情况下是私有的,我们可以通过这种方法来封装一些代码的实现细节。

OK,回到刚才的问题,那我们怎么才能解决这个错误呢?地球人都知道应该把对应的模块与函数公开出来。Rust中标识模块或函数为公有的关键字是pub

我们用pub关键字来把对应的模块和函数公开

05-2

这样我们就可以在module外来调用module内的函数了。

Rust中的私有规则

现在我们再回过头来看Rust中的一些私有规则,如果你试验了上面的例子,也许会有一些发现。

Rust中私有规则适用于所有项(函数、方法、结构体、枚举、模块和常量),它们默认都是私有的。父模块中的项不能访问子模块中的私有项,而子模块中的项可以访问其祖辈(父模块及以上)中的项。

Struct和Enum的私有性

Struct和Enum的私有性略有不同,对于Struct来讲,我可以只将其中的某些字段设置为公有的,其他字段可以仍然保持私有。

mod back_of_house {     pub struct Breakfast {         pub toast: String,         seasonal_fruit: String,     }      impl Breakfast {         pub fn summer(toast: &str) -> Breakfast {             Breakfast {                 toast: String::from(toast),                 seasonal_fruit: String::from("peaches"),             }         }     } }  pub fn eat_at_restaurant() {     // Order a breakfast in the summer with Rye toast     let mut meal = back_of_house::Breakfast::summer("Rye");     // Change our mind about what bread we'd like     meal.toast = String::from("Wheat");     println!("I'd like {} toast please", meal.toast); }

而对于Enum,如果一个Enum是公有的,那么它的所有值都是公有的,因为私有的值没有意义。