Package & Crate
package 及 crate 是 Rust 的模块系统里的概念,一个 package 中可以包含一个或多个 crate ,而 crate 可以看成是 package 暴露的能力,crate 的表现可以是 library 或者 binary 。package 中可以通过 Cargo.toml 来告诉编译器如何构建其中的 crate ,一个 package 中至少要有一个 crate 。
可能会有点抽象,但是只要理解 crate 在项目中具体是什么就能理解了。可以执行下面这个指令
$ cargo new mylib --lib
会自动创建一个 mylib 的项目,结构如下
mylib├── Cargo.toml└── src└── lib.rs
其中 mylib 就是 packge ,src/lib.rs就是同名的 library crate 。
此时也可以在 src 下加个 main.rs ,加了之后,mylib 这个 package 里就有两个 crate 了,一个是 src/lib.rs 作为 library crate,还有一个就是 main.rs 编译后产生的 binary crate( 即编译出来的二进制可执行文件 target/mylib )。用户使用这个 mylib 既可以使用 mylib 的 library 暴露的能力,也可以使用 mylib 里的 binary 。所以前面才会说,crate 可以认为是 package 暴露的能力。
一个 package 中只能包含一个 library crate( 因为 src/lib.rs 只能有一份呐 ),但是可以包含多个 binary crate ( src/main.rs 是一个,如果想要更多的 binary ,在 src/bin 目录下建的每一个 rs 文件都会编译成一个与文件名同名的 binray )
Modules
Rust 也支持通过模块的方式来组织代码,模块可以声明在同个文件里,如下
注意,只有加了 pub 前缀的函数,才会暴露出去。
// src/lib.rsmod test_mod {pub fn test() -> u8 {1}}pub fn test() -> u8 {let i = test_mod::test();i}#[cfg(test)]mod tests {use crate::test;#[test]fn it_works() {assert_eq!(test(), 1);}}
执行 cargo test 即可验证逻辑。上面的逻辑可以看到通过 :: 可以调用模块内部暴露的方法,同时也可以使用 use 来直接引入对应的函数,参考 tests 这个 module 下的 use crate::test ( crate 代表 library ),因为在 tests 中是直接 use 了 lib 下的 test 函数,所以后面的单测中就可以直接执行 test 方法了。
跑 cargo test 会自动执行 tests 这个模块下的所有测试
模块还可以定义到其他文件,比如上面的 test_mod 可以到 src/test_mod.rs 中
// src/test_mod.rspub fn test() -> u8 {1}
lib.rs 里的代码就可以改成
// src/lib.rsmod test_mod;pub fn test() -> u8 {let i = test_mod::test();i}
也可以用 use 把 test_mod 里的 test 方法引入进来,因为 lib 下就有个 test 了,所以可以用 as 将 test_mod 里的 test 换成其他名称。
// src/lib.rsmod test_mod;use test_mod::test as test_mod_fn;pub fn test() -> u8 {let i = test_mod_fn();i}
test_mod 里也可以快速引入其他同名目录下的模块。比如新建一个 test_mod 目录,里面加个 test 函数
// src/test_mod/sub_mod.rspub fn test() -> u8 {1}
那么在 test_mod.ts 中也可以便捷的引入该 module( 因为会查同名目录也就是 src/test_mod/ 下的模块 )
// src/test_mod.rsmod sub_mod;pub fn test() -> u8 {sub_mod::test()}
在这些子模块里,也可以通过 crate::的方式,引入 library 中的其他模块,比如我在 lib.rs 有个 util 的模块。
// src/lib.rsmod test_mod;mod util {pub fn test() -> u8 { 1 }}use test_mod::test as test_mod_fn;pub fn test() -> u8 {let i = test_mod_fn();i}
在 src/test_mod/sub_mod.rs 中就可以通过 crate 获取到这个 mod 并且进行使用
// src/test_mod/sub_mod.rspub fn test() -> u8 {crate::util::test()}
总结就是
- lib.rs 中可以通过
mod xxx的方式引入 src 下的模块。 - 子模块可以通过
crate::xxx的方式获取到 lib.rs 中声明的模块。 - 子模块可以通过
mod xxx的方式引入同名目录下的子模块( 如果要暴露子模块,需要pub mod xxx)。
