Rust官方的模块系统教程太啰嗦了,以下内容根据官方教程精简。
Crate
crate 是 Rust 在编译时最小的代码单位。一个crate是一个源文件。
crate 有两种形式:二进制 crate 和库 crate。
- 二进制 crate(Binary crates)必须有一个名为 main 的函数,可以被编译为可执行程序,比如命令行程序或者服务端。
- 库 crate(Library crates)并没有 main 函数,它们也不会编译为可执行程序。相反它们定义了可供多个项目复用的功能模块,这与其他编程语言中 “library” 概念一致。
crate root 是一个源文件,Rust 编译器以它为起始点编译代码。
Cargo 遵循一个约定:
- src/main.rs是一个与包同名的二进制 crate 的 crate root。
- src/lib.rs是一个与包同名的库 crate 的 crate root。
包(Packages)
包(package)是提供一系列功能的一个或者多个 crate 的捆绑。一个包会包含一个 Cargo.toml 文件。
Cargo创建的项目就是一个包。
一个包(package)可以包含多个二进制 crate 项和一个可选的库 crate。
通过将文件放在 src/bin 目录下,一个包可以拥有多个二进制 crate:每个 src/bin 下的文件都会被编译成一个独立的二进制 crate。
模块(Modules)
模块让我们可以将一个 crate 中的代码进行分组,以提高可读性与重用性。因为一个模块中的代码默认是私有的,所以还可以利用模块控制项的私有性(Privacy) 。私有项是不可为外部使用的内在详细实现。我们也可以将模块和它其中的项标记为公开的,这样,外部代码就可以使用并依赖于它们。
声明模块: 在 crate root 文件中,使用 mod 关键字声明一个新模块。例如:内联定义模块:将声明模块后的分号改为大括号,其中提供模块代码。例如:- mod garden {
- // 模块中可定义函数、结构体、枚举、常量、trait等。
- }
复制代码 在单独的文件中定义模块:当在crate 根文件中声明了一个模块,例如mod garden;,在src/garden.rs文件中定义模块代码。当在garden.rs中声明了子模块vegetables,则在src/garden/vegetables.rs文件中定义子模块代码。
隐式根模块:src/main.rs 和 src/lib.rs 这两个文件的内容在 crate 模块结构的根组成了一个名为 crate 的模块。
模块树(module tree):模块结构是树状结构。
公开模块成员
模块里的成员默认对父模块私有。为了公开模块中的成员,应当在声明前使用pub。
子模块
在模块中声明模块,即子模块。例如在src/garden.rs文件中:为了公开子模块,声明时使用 pub mod 替代 mod。结构体
模块中,结构体的字段也是默认私有的,需要使用pub公开字段:- 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"),
- }
- }
- }
- }
复制代码 以上代码,因为 back_of_house::Breakfast 具有私有字段,所以这个结构体需要提供一个公共的关联函数来构造 Breakfast 的实例。
枚举
如果将枚举设为公有,则它的所有变体都将变为公有。- mod back_of_house {
- pub enum Appetizer {
- Soup,
- Salad,
- }
- }
复制代码 调用模块成员
为了调用模块中的成员,要完整指定成员的路径,多层路径之间用双冒号(::)分割。路径有两种形式:
- 绝对路径(absolute path)是以 crate 根(root)开头的完整路径;对于外部 crate 的代码,是以 crate 名开头的绝对路径,对于当前 crate 的代码,则以字面值 crate 开头。
- 相对路径(relative path)从当前模块开始,以 self、super 或当前模块中的某个标识符开头。
例如:- mod front_of_house {
- pub mod hosting {
- pub fn add_to_waitlist() {}
- }
- }
- pub fn eat_at_restaurant() {
- // 绝对路径
- crate::front_of_house::hosting::add_to_waitlist();
- // 相对路径
- front_of_house::hosting::add_to_waitlist();
- }
复制代码 可以通过在路径的开头使用 super ,从父模块开始构建相对路径,调用父模块成员:- fn deliver_order() {}
- mod back_of_house {
- fn fix_incorrect_order() {
- cook_order();
- super::deliver_order();
- }
- fn cook_order() {}
- }
复制代码 用use 关键字引入模块成员
使用use 关键字引入模块成员,以便减少调用成员编写过长的路径。
例如引入子模块:- 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();
- }
复制代码 引入结构体:- use std::collections::HashMap;
- fn main() {
- let mut map = HashMap::new();
- map.insert(1, 2);
- }
复制代码 通常只引入结构体、枚举和子模块,而不直接引入函数。在调用函数时指定其模块,这样可以清晰地表明函数不是在本地定义的,同时使完整路径的重复度最小化。
use引入的成员只在当前作用域起作用,在子模块中是另一个作用域,不起作用:- mod front_of_house {
- pub mod hosting {
- pub fn add_to_waitlist() {}
- }
- }
- use crate::front_of_house::hosting;
- mod customer {
- pub fn eat_at_restaurant() {
- hosting::add_to_waitlist(); // 此处编译报错
- }
- }
复制代码 使用 as 关键字指定别名
不能引入两个同名类型,除非给其中一个类型指定别名。- use std::fmt::Result;
- use std::io::Result as IoResult;
- fn function1() -> Result {
- // --snip--
- }
- fn function2() -> IoResult<()> {
- // --snip--
- }
复制代码 使用 pub use 重导出名称
使用 use 关键字,将某个名称导入当前作用域后,该名称对此作用域之外还是私有的。若要让作用域之外的代码能够像在当前作用域中一样使用该名称,可以将 pub 与 use 组合使用。这种技术被称为重导出(re-exporting),因为在把某个项目导入当前作用域的同时,也将其暴露给其他作用域。
例如在restaurant包中:- mod front_of_house {
- pub mod hosting {
- pub fn add_to_waitlist() {}
- }
- }
- pub use crate::front_of_house::hosting;
- pub fn eat_at_restaurant() {
- hosting::add_to_waitlist();
- }
复制代码 在这个修改之前,外部代码需要使用路径 restaurant::front_of_house::hosting::add_to_waitlist() 来调用 add_to_waitlist 函数,并且还需要将 front_of_house 模块标记为 pub。现在这个 pub use 从根模块重导出了 hosting 模块,外部代码现在可以使用路径 restaurant::hosting::add_to_waitlist。
通过 glob 运算符引入成员
如果希望将一个路径下所有公有项引入作用域,可以指定路径后跟 * glob 运算符:使用 glob 运算符时请多加小心!glob 会使得我们难以推导作用域中有什么名称和它们是在何处定义的。
glob 运算符经常用于测试模块 tests 中,这时会将所有内容引入作用域。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |