Managing Growing Projects with Packages, Crates, and Modules
Packages and Crates
Package
Package(包) : Cargo 的特性,让你构建、测试、共享 crate
Crate(单元包) : 模块树,它可产生一个 library 或可执行文件
Module(模块), use : 让你控制代码的组织、作用域、私有路径
Path(路径) : 为 struct、function 或 module 等项命名的方式
Cargo 的惯例
src/main.rs:
- binary crate 的 crate root
- crate 名与 package 名相同
src/lib.rs:
- package 包含一个 library crate
- library crate 的 crate root
- crate 名与 package 名相同
一个 package 可以同时包含 src/main.rs 和 src/lib.rs
- 名称与 package 名相同
一个 package 可以有多个 binary crate:
- 文件放在 src/bin
- 每个文件是单独的 binary crate
一个 package 最多有一个个 library crate:
Defining Modules to Control Scope and Privacy
module
Module:
- 在一个 crate 内,将代码进行分组
- 增加可读性,易于复用
- 控制项目(item)的私有性。public、private
建立 module:
- 使用 mod 关键字
- 可以嵌套
例如
mod front_of_house {
mod hosting {
fn add_to_waiting() {}
}
}
pub
关键字
pub struct:
- struct 是公共的
- struct 的字段默认私有
例如
mod front_of_house {
pub struct Breakfast {
pub toast: String,// public
seasonal_fruit: String,// private
}
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
}
fn eat_at_restaurant() {
let mut meal = front_of_house::Breakfast::summer("Rye");
meal.toast = String::from("Wheat");
meal.seasonal_fruit = String::from("blue");// Error! private field
}
Paths for Referring to an Item in the Module Tree
Path
绝对路径:从 crate root 开始,使用 crate 名 或 字面值 crate
相对路径:从 当前模块开始,使用 self,super 或当前模块的标识符
mod front_of_house {
mod hosting {
fn add_to_waiting() {}
}
}
fn eat_at_restaurant() {
// 绝对路径
crate::front_of_house::hosting::add_to_waiting();
//相对路径
front_of_house::hosting::add_to_waiting();
}
Cargo run 会发现错误
/*
house::hosting::add_to_waiting();
| ^^^^^^^ -------------- function `add_to_waiting` is not publicly re-exported
| |
| private module
*/
这就是因为默认私有,使用 pub
关键字将条目标记为公共的
mod front_of_house {
pub mod hosting {
pub fn add_to_waiting() {}
}
}
父级模块无法访问子模块中的私有条目
子模块可以访问所有祖先模块中的条目
super
关键字,表示上一级
mod front_of_house {
pub mod hosting {
pub fn add_to_waiting() {
super::get();// 调用上一级的 get
}
}
fn get() -> String {
return String::from("2024");
}
}
Bringing Paths into Scope with the use
Keyword
遵守私有性原则
一般将函数的的父级引入模块
struct,enum,其他:指定完整路径(指定到本身)
mod front_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"),
}
}
}
}
use crate::front_of_house::Breakfast;// 绝对路径
fn eat_at_restaurant() {
Breakfast::summer("abc");//这时候就可直接用
}
同名条目:指定到父级
use std::fmt;
use std::io;
fmt::Result;
io::Result;
as
关键字
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;
这时候就可以直接用 as 后的东西代替前面的东西
use
引入默认私有,外部代码看不到
fn eat_at_restaurant() {
use crate::front_of_house::Breakfast; // 外部看不到
let x = Breakfast::summer("abc");
println!("{:#?}", x);
}
fn eat_at_restaurant() {
pub use crate::front_of_house::Breakfast;// 外部看得到
let x = Breakfast::summer("abc");
println!("{:#?}", x);
}
使用外部包 package
Cargo.toml 下添加 package
package 下载 https://crates.io/
// Cargo.toml 下
[dependencies]
rand = "0.7.3"
// package
需要 cargo build, 下载慢可以换国内镜像源
使用 use 将特定条目引入作用域
use rand::Rng;
std 默认内置(即不需要在 dependencies 放 package),但需要用 use 来引入作用域
例如引入 HashMap
use std::collections::HashMap;
使用嵌套路径清理大量 use 语句
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::BTreeMap;
我们发现前面都是一样的
使用语法 相同部分::{不同部分,...}
use std::collections::{HashMap, HashSet, BTreeMap};
当我们需要本身和它下面的条目时,使用 self
例如:引入 std::collections 和 std::collections::HashMap
use std::collections::{self, HashMap};// self
当我们需要一个模块下所有条目时,我们可以使用通配符 *
来引入
use std::collections::*;
一般测试时才会用
Separating Modules into Different Files
将模块内容移动到其他文件
模块定义时,如果模块名后面是;
,而不是代码块{code}
,rust 会从与模块同名的文件中加载内容,模块树结构不会变化
// lib.rs 内
mod hosting;
// hosting.rs 内
mod hosting {
// code
}
如果是嵌套模块,需要放到对应文件夹下