Package 和 Crate
Crate
src/main.rs
- binary crate 的 crate 根
- crate 名称与 package 名称相同
src/lib.rs
- package 包含一个 library crate
- library crate 的 crate 根
- crate 名称与 package 名称相同
cargo 会把 crate root 文件交个rustc 来构建library或者binary文件
由此可得出结论:
- 一个Package了可以同时包含src/main.rs和src/lib.rs,即为一个binary crate一个library crate,两个crate名称都与package名相同
- 一个Package可以有多个binary crate:放在src/bin下面的文件每一个都是单独的binary crate
Crate作用
- 将相关功能组合到一个作用域内,便于在项目之间进行共享
- 防止命名冲突
定义Module Module
- 在一个Crate中将代码进行分组
- 增加可读性,易于复用
- 控制属性的public、private
定义一个mod: mod关键字 可嵌套 可包含其他内容(struct、enum、常量、trait、函数)的定义,示例:
mod front_of_house {
mod hosting{
fn add_to_waitlist(){}
fn seat_at_table(){}
}
mod serving {
fn takeorder(){}
fn server_order(){}
fn take_payment(){}
}
}
src/main.rs 和 src/lib.rs 叫做 create roots, 这两个文件(任意一个)的内容形成了名为crate的模块,位于整个模块树的根部
路径
绝对路径:从crate root开始,使用crate名 或 字面值crate
相对路径: 从当前模块开始,使用self、super(上一级)或当前模块的标识符
路径至少有一个标识符组成,标识符之间用 :: 分割,示例:
// src/lin.rs
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::hosting() // 相对路劲写法,因为是同一级的可以直接引用
}
报错了,why???
私有边界
- 模块不仅可以组织代码,还可以定义私有边界
- 如果想把函数 或者 struct 等设置为私有,可以将它直接放到某个模块中
- Ruts中的所有条目默认都是私有的
- 父级模块无法访问子模块中的私有条目
- 子模块里可以使用所有祖先模块中的条目
Rust希望默认细节是隐藏的,这样可以知道修改那些代码不会破坏外部的内容。(想用必须得声明好,这就很rust了)
回到刚刚的报错:error[E0603]: module hosting is private , 如何解决这个报错呢?
关键字
pub
pub: 将条目标记为公共的,它就可以解决上述报错了,示例:
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::hosting() // 相对路劲,因为是同一级的可以直接引用
}
将pub放在struct前:
- struct是公共的
- struct里的字段默认是私有的,需要单独设置pub来变成公有
mod back_of_house{
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
impl Breakfast {
pub fn summery(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::summery("Rye");
meal.toast = String::from("Wheat");
println!("I'd like {} toast please",meal.toast);
// meal.seasonal_fruit = String::from("blueberries") // 因为seasonal_fruit没有定义pub,所以这里如何打开则编译报错
}
pub 在 enum 前: 枚举和枚举里的所有变体都是公共的
super
super: 用来访问父级模块中的内容,类似文件系统的 .. 示例:
// src/lin.rs
fn serve_order(){}
mod back_of_house{
fn cook_order(){
println!("cook_order")
}
fn fix_incorrect_order(){
cook_order();
// crate::serve_order()
super::serve_order() // 这里和上面注释掉的一行是一模一样的
}
}
use
可以使用use关键字将路径导入到作用域内
- 扔遵循私有性规则 示例:
use的习惯用法
- 针对函数,通常去引用父级模块,以便于知道是是哪里的函数
- struct、enmu等,导入通常指定完整路径(到它本身)
- 但是不同模块的同名条目,引用还是要指定到父级模块 示例:
// src/lin.rs
mod front_of_house {
pub mod hosting{
pub fn add_to_waitlist(){}
fn private_function(){}
}
}
use front_of_house::hosting;
pub fn eat_at_restaurant(){
hosting::add_to_waitlist();
// hosting::private_function(); // 打开注释则会报错,和上述私有属性一样的错误
}
as
为引入的路径指定本地的别名(和js一样)
mod front_of_house {
pub mod hosting{
pub fn add_to_waitlist(){}
fn private_function(){}
}
}
use crate::front_of_house::hosting as newhost;
fn main(){
newhost::add_to_waitlist();
}
使用外部包
在Cargo.toml 中添加依赖的包,之后运行 cargo build 时候程序会 crates.io 寻找并下载依赖库(不能科学上网会有点卡,自行百度切换源即可) 示例:
# 修改 Cargo.toml
[package]
name = "variables"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.5"
use rand::Rng;
fn main() {
// 生成一个0~9的的随机数,gen_range 根据Rust 版本不同参数写法上也是有区别的需要注意
// 较新版本的是 gen_range(0,10)
let randnum = rand::thread_rng().gen_range(0..10);
println!("Rand num is : {}", randnum);
}
将模块分割进不同文件
(这块很有意思,对我这种基础不太好的产生了另一种思考方式) 当前我们都是将所有模块放到一个文件中,而当模块变得更大时,一个文件是无法承载如此多的内容的, 此时我们可以拆分文件,而rust有如下解析机制:
- 模块定义时如果模块名后面是“;” ,而不是代码块,则rust会从与模块同名的文件或文件夹中加载模块
- 无论如何加载,模块数的结构不会发生变化
示例:
// src/front_of_house.rs
pub mod hosting{
pub fn add_to_waitlist(){}
fn seat_at_table(){}
}
// src/lib.rs
mod front_of_house;
use crate::front_of_house::hosting;
fn eat_at_restaurant(){
hosting::add_to_waitlist();
}
当front_of_house文件又变得更大的时候我们可以继续拆分,按照结构,此时仿照lib.rs改变front_of_house.rs内代码:
// src/front_of_house.rs
pub mod hosting;
接着,创建一个名为front_of_house的文件夹,并在文件夹下创建一个 hosting.rs文件,结构变为 此时hosting.rs文件:
// src/front_of_house/hosting.rs
pub fn add_to_waitlist(){}
pub fn seat_at_table(){}
之后即可正常运行了。