package、crate、定义moudule
- rust的代码组织
- 代码组织主要包括
- 哪些细节可以暴露,哪些细节是私有的
- 作用域内哪些名称有效
- 模块系统
- package(包):cargo的特性,让你构建、测试、共享crate
- crate(单元包):一个模块树,它可产生一个libraty或可执行文件
- module(模块)、use:让你控制代码的组织、作用域、私有路径
- path(路径):为struct、Function、module等项命名的方式
- 代码组织主要包括
- pacakge 和 Crate
- crate的类型:
- binary
- library
- crate root:
- 是源代码文件
- rust编译器从这里开始,组成你的crate的根module
- 一个package:
- 包含1个cargo.toml,它描述了如何构建这些crates
- 只能包含0-1个library crate
- 可以包含任意数量的binary crate
- 但必须至少包含一个crate(libraty 或 binary)
- crate的类型:
- cargo的惯例
- src/main.rs:
- binary crate 的 crate tool
- crate名与package名相同
- src/lib.rs:
- package包含一个library crate
- library crate 的 crate tool
- crate名与package名相同
- cargo 把 crate root 文件交给rustc来构建library或binary
- 一个package可以同时包含src/main.rs和src/lib.rs
- 一个binary crate,一个library crate
- 名称与package名相同
- 一个package可以有多个binary crate:
- 文件放在src/bin
- 每个文件是单独的binary crate
- src/main.rs:
- crate的作用
- 将相关功能组合到一个作用域内,便于在项目间进行共享
- 防止冲突
- 例如 rand crate,访问它的功能需要通过它的名字:rand
- 将相关功能组合到一个作用域内,便于在项目间进行共享
- 定义moudule来控制作用域和私有性
- module
- 在一个crate内,将代码进行分组
- 增加可读性,易于复用
- 控制项目的私有性。public、private
- 建立module:
- mod关键字
- 可嵌套
- 可包含其它项(struct、enum、常量、trait、函数等)的定义
- module
- module
- src/main.rs和src/lib.rs叫做crate roots:
- 这两个文件(任意一个)的内容形成了名为crate的模块,位于整个模块树的根部
backyard ├── Cargo.lock ├── Cargo.toml └── src ├── garden │ └── vegetables.rs ├── garden.rs └── main.rs - src/main.rs和src/lib.rs叫做crate roots:
路径path
- 为了在rust的模块中找到某个条目,需要使用路径。
- 路径的两种形式
- 绝对路径: 从crate root开始,使用crate名或字面值crate
- 相对路径:从当前模块开始,使用self,super或当前模块的标识符
- 路径至少由一个标识符组成,标识符之间全用::.
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
- 私有边界
- 模块不仅可以组织代码,还可以定义私有边界
- 如果想把函数或struct等设为私有,可以将它放到某个模块中
- Rust 中所有的条目(函数、方法、struct、enum、模块、常量)默认是私有的
- 父级模块无法访问子模块的私有条目
- 子模块里可以使用所有祖先模块中的条目
- pub 关键字
- 使用pub关键字来将某些条目标记为公共的
- super关键字
- 上一级路径
fn deliver_order() {} mod back_of_house { fn fix_incorrect_order() { cook_order(); super::deliver_order(); } fn cook_order() {} } - pub stuct
- pub放在struct前:
- struct是公共的
- struct的字段默认是私有的
- struct的字段需要单独设置pub来变成共有
- pub放在struct前:
- pub enum
- pub放在enum前:
- enum是公共的
- enum的变体也都是公共的
- pub放在enum前:
- use关键字
- 可以使用use关键字将路径导入到作用域内
- 仍遵循私有性规则
- 使用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(); } - use的习惯用法
- 函数:将函数的父级模块引入作用域(指定到父级)
- struct,enum,其它:指定完整路径(指定到本身)
- 同名条目:指定到父级
- 可以使用use关键字将路径导入到作用域内
- 使用pub use 重新导出名称
- 使用use将路径(名称)导入到作用域内后,该名称在此作用域内是私有的
- pub use:重导出
- 将条目引入作用域
- 该条目可以被外部代码引入到它们的作用域
- 使用外部包
- cargo.toml添加依赖包(package)
- use 将特定条目引入作用域
- 标准库(std)也被当作外部包
- 不需要修改 cargo.toml来包含std
- 需要使用use将std中的特定条目引入当前作用域
cd ~/.cargo touch config
- 使用嵌套路径清理大量的use语句
- 如果使用同一个包或模块下的多个条目(例子)
- 可使用嵌套路径在同一行内将上述条目进行引入:
- 路径相同的部分::{路径差异的部分}
- 如果两个use路径之一是另一个的子路径
- 使用self
use rand::Rng; // --snip-- use std::{cmp::Ordering, io}; // --snip-- fn main() { println!("Guess the number!"); let secret_number = rand::thread_rng().gen_range(1..101); println!("The secret number is: {}", secret_number); println!("Please input your guess."); let mut guess = String::new(); io::stdin() .read_line(&mut guess) .expect("Failed to read line"); let guess: u32 = guess.trim().parse().expect("Please type a number!"); println!("You guessed: {}", guess); match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => println!("You win!"), } }
- 通配符 *
#![allow(unused)] fn main() { use std::collections::*; }
将模块内容称动到其它文件
- 将模块内容移动到其它文件
- 模块定义时,如果模块名后边是“;”,而不是代码块:
- rust会从与模块同名的文件中加载内容
- 模块树的结构不会变化
- 随着模块逐渐变大,该技术让你可以把模块的内容移动到其它文件中
- 模块定义时,如果模块名后边是“;”,而不是代码块:
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}