package 和 crate
- package(包): Cargo 的特性, 可构建/测试/共享 crate
- crate(单元包): 一个模块树, 可产生一个 libary 或 binary
- module/use(模块): 控制代码的组织方式, 作用域, 私有路径
crate 类型
- binary
- libary
Crate Root
- 源代码文件入口
- Rust 编译器从这里开始, 组织 Crate 的根 Module
Package
- 包含一个
Cargo.toml
描述了如何构建这些crates
- 只能包含 0-1 个 libary crate
- 可以宝航任意数量的 binary crate
- 但是至少要包含一个 crate(libary 或 binary)
Cargo crate Root的惯例
Cargo 把 crate root 文件交给 rustc 来构建 libary 或 binary
一个 package 可以同时包含
src/main.rs
和src/lib.src
, 一个是 binary crate 的入口文件(root), 一个是 libary crate 的入口文件(root)一个 package 可以有多个 binary crate, 文件放在
src/bin
, 每个文件都是单独的 crate
src/main.rs
- binary crate 的 crate root
- crate 名与 package 名相同
src/lib.rs
- package 包含一个 libary crate
- libary crate 的 crate root
- crate 名与 package 名相同
crate 的作用
- 将相关的功能组合到一个作用域内, 便于在项目之间进行共享
- 防止命名冲突
- 例如生成随机数的 rand 就是一个 crate, 访问他需要通过他的 package 名
rand
定义 module
- 将代码分组, 易于管理代码
- 增加可维护性, 易于复用
- 控制项目(item)的私有性, public private 等
- module 是可嵌套的
- 模块默认是私有的, 如果要外部可以使用就需要使用
pub
关键字
1.创建 cargo 项目
sh
# 注意名字,后续再使用绝对路径的时候会用到
cargo new modsys;
2.创建 libary root
创建模块的入口文件: src/lib.rs
rs
pub mod math {
pub mod rand {
pub fn random() {
println!("取随机数");
}
pub fn range() {
println!("在范围中取随机数");
}
}
pub mod take_integer {
pub fn ceil() {
println!("向上取整");
}
pub fn call_anthor_mod_fn() {
// 通过模块路径调用其他模块的方法
crate::math::rand::random();
println!("测试调用其他模块");
}
// 模块和方法, 默认是私有的, 如果不加 pub 关键字
// 在外部无法使用, 只能在这个文件中使用
// 可能会让编译器报警告: function `floor` is never used
fn floor() {
println!("向下取整");
}
}
}
3.使用 libary
rs
// 使用 use 关键字导入模块
// 不能导入私有模块/方法, 如 floor 方法
use modsys::math::rand; // 1.导入整个模块
use modsys::math::take_intger::ceil; // 2.导入模块下具体方法
use modsys::math::take_intger::call_anthor_mod_fn;
// 上面这样的方式有些太麻烦了
// 使用 {} 可以一次导入多个模块或具体方法
// use modsys::math::{rand, take_intger};
// use modsys::math::rand::{random, range};
// 使用 * 可以一次导入全部模块/方法
// use modsys::math::*;
// use modsys::math::rand::*;
fn main() {
rand::random();
rand::range();
ceil();
call_anthor_mod_fn();
}
4. 使用 as 关键字解决重名问题
rust
// 假设有两个这样的模块, 都有 read 方法
// 那么使用 as 关键字就可以解决问题
use fs::read as readFile;
use buffer::read as readBuffer;
fn main() {
// 这样使用即可, 不会命名冲突
readFile();
readBuffer();
}
将模块拆分为多个文件(推荐)
上面代码介绍了如何定义和使用模块, 但是问题是, 所有模块都在一个文件中 src/lib.rs
这其实是不太合理的, 如果一个模块文件内容比较多, 全部放到一个文件中, 就会导致这个文件特别大, 难以维护
既然已经学会了如何定义和使用模块, 那就直接上代码
文件目录结构
txt
.
├── Cargo.lock
├── Cargo.toml
└── src
├── lib.rs
├── main.rs
└── math
├── rand.rs
└── take_integer.rs
文件内容
rs
// 导入并使用其他模块
use modsys::math::rand;
use modsys::math::take_integer::*;
fn main() {
rand::random();
rand::range();
ceil();
floor();
call_anthor_mod_fn();
}
rs
// 只定义了模块, 但是并没有具体实现
// 注意模块路径和要和文件路径一致
// math -> src/math
// rand -> src/math/rand
// take_integer -> src/math/integer
pub mod math {
pub mod rand;
pub mod take_integer;
}
rs
pub fn random() {
println!("取随机数");
}
pub fn range() {
println!("在范围中取随机数");
}
rs
// 在一个模块中使用另外一个模块的功能
use crate::math::rand::random;
pub fn ceil() {
println!("向上取整");
}
pub fn floor() {
println!("向下取整");
}
pub fn call_anthor_mod_fn() {
random();
println!("导入测试其他模块的方法");
}
使用 pub use 关键字调整导出结构
上面的例子可以看到, 虽然说, 这样规划mod在开发时是比较合理的, 但是在使用的时候就比较费劲, 可否在 ./lib.rs
中直接导出方法, 导入是直接忽略这些模块
rust
// 导入并使用其他模块
// use modsys::math::rand;
// use modsys::math::take_integer::*;
// 直接导入
use modsys::{ rand, take_integer, call_anthor_mod_fn };
fn main() {
rand::random();
rand::random();
rand::range();
take_integer::ceil();
take_integer::floor();
call_anthor_mod_fn();
}
rust
// 只定义了模块, 但是并没有具体实现
// 注意模块路径和要和文件路径一致
// math -> src/math
// rand -> src/math/rand
// take_integer -> src/math/integer
// 重新导出模块(让导入的时候可以不用按照文件路径)
pub use crate::math::rand;
pub use crate::math::take_integer;
pub use crate::math::take_integer::call_anthor_mod_fn;
pub mod math {
pub mod rand;
pub mod take_integer;
}