Hello Rust [4] - 模块
包和Crate
crate 是一个二进制项或者库, crate root是一个源文件。
Rust编译器以它为起始点,并构成你的crate的根模块。
包中所包含的内容由几条规则来确立。
- 包中可以包含最多一个库crate
- 包中可以包含任意多个二进制crate
- 至少包含一个crate,二进制或者库
模块
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,语法如上。 - 在模块内部,可以定义其他的项:结构体,枚举,常量,特性,函数
src/main.rs和src/lib.rs叫做crate根- 这两个文件都分别在crate模块的根组成一个叫
crate的模块,该结构被称为 模块树 (module tree)
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
模块路径
有两种路径:
- 绝对路径(absolute path):从
crate根开始,以crate名或者字面值crate开头。 - 相对路径(relative path):从当前模块开始,以
self,super或当前模块的表示开头。
绝对路径和相对路径都后面更一个或者多个由双冒号(::)分割的标识符。
下面是一个例子:
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径
front_of_house::hosting::add_to_waitlist();
}
- rust中,默认所有项都是私有的。父模块不能使用子模块中的私有项,子模块可以使用父模块的项。
- pub 可以用于暴露路径。
mod front_of_house {
pub mod hosting {
// 这里,每个方法都要是pub的才能访问
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
super开始的路径类似于文件系统中的../
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}
fn cook_order() {}
}
公有结构体和枚举
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() {
// 在夏天订购一个黑麦土司作为早餐
let mut meal = back_of_house::Breakfast::summer("Rye");
// 改变主意更换想要面包的类型
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
// 如果取消下一行的注释代码不能编译;
// 不允许查看或修改早餐附带的季节水果
meal.seasonal_fruit = String::from("blueberries");
}
- 对于结构体,每个字段都默认为私有,你需要手动声明字段是否公有
- 对于枚举,当枚举为公有,则其所有成员都为公有
USE -- 简化路径调用
为了避免每次都写非常冗长的路径调用,我们可以使用use,类似于import:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
// 或者是使用相对路径的导入
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
- 指定到hosting而不是
add_to_waiting的好处在于区分模块
可以使用as重命名,类似于:
use std::fmt::Result;
use std::io::Result as IoResult;
使用pub use重新导出:
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();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
使用嵌套路径来消除use:
use std::cmp::Ordering;
use std::io;
// ==>
use std::{cmp::Ordering, io};
使用glob运算符批量导入:
use std::collections::*;
Cargo.toml 外部包
rand = "0.8.3"
在仓库中:
use rand::Rng;
// ...
在根中导入所有模块
将多个模块分散到不同的文件中时,我们只需要在根文件中导入所有mod就可以了:
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}