模块化编程
- 模块(module)
- 箱(crate)
- 包(package)
- 工作空间(workspace)
箱(crate)
箱是一个独立的可编译单元,它编译后会生成一个可执行文件或者一个库。
箱可以包含多个模块,每个模块可以包含多个文件。
- 可执行箱:必须有一个
main
函数来定义程序的执行入口 - 库箱:没有
main
函数,不会被编译为可执行程序。- 编译库箱,使用
rustc --crate-type=lib
参数
- 编译库箱,使用
注意:箱之间不能存在循环依赖
rust
pub fn public_function() {
println!("public_function");
}
fn private_function() {
println!("private_function");
}
pub fn indirect_access() {
println!("indirect_access");
private_function();
}
bash
rustc --crate-type=lib myfunc.rs
// libmyfunc.rlib
// 生成的文件名必须lib开头,否则会报错
rust
fn main() {
println!("main");
myfunc::indirect_access();
myfunc::public_function();
// 无法访问私有函数
// myfunc::private_function();
// | ^^^^^^^^^^^^^^^^ private function
}
bash
rustc --extern myfunc=libmyfunc.rlib main.rs --edition=2021
./main
# ➜ src git:(master) ✗ ./main
#main222
#indirect_access
#private_function
#public_function
#➜ src git:(master) ✗
命令参考:
--crate-type:编译器生成包的类型列表
指示rustc要构建的crate类型。该标志接受逗号分隔的值列表,并且可以多次指定。有效的crate类型为:
- lib—生成编译器首选的库类型,当前默认为 rlib。
- rlib — Rust静态库。
- staticlib —原生静态库。
- dylib — Rust动态库。
- cdylib —原生动态库。
- bin —可运行的可执行程序。
- proc-macro —生成适合于程序宏类库的格式,该格式可由编译器加载。
包(package)
包(package)用于项目级管理,包中可以包含多个箱。
一个包会包含一个 Cargo.toml
文件,该文件描述了包信息,包括箱名称、版本、依赖项等。
包中可以包含最多一个库箱(library crate),多个可执行箱(binary crate)。但是必须至少包含一个箱。
bash
cargo new --bin my_project
bash
➜ my_project git:(master) ✗ tree
.
├── Cargo.toml
└── src
└── main.rs
2 directories, 2 files
➜ my_project git:(master) ✗
bash
cargo run
bash
cargo build
bash
cargo new --lib my_lib
bash
➜ my_lib git:(master) ✗ tree
.
├── Cargo.toml
└── src
└── lib.rs
2 directories, 2 files
➜ my_lib git:(master) ✗
toml
[lib]
name = "my_lib"
crate-type = ["rlib", "cdylib", "staticlib"]
toml
[package]
name = "my_lib"
version = "0.1.0"
edition = "2021"
[dependencies]
# 引用其他库
mylib= { path = "../mylib" }
[lib]
name = "my_lib"
crate-type = ["rlib", "cdylib", "staticlib"]
bash
cargo build
Rust支持的库有以下几种
- rlib:Rust库(默认)只能被Rust调用
- dylib:Rust动态链接库,Windows上编译成.dll文件,Linux上编译成.so文件,也只能被Rust调用
- cdylib:满足C语言规范的动态链接库,可以被其他语言调用
- staticlib:静态库,windows上编译成.lib文件,linux上编译成.a文件,可以被其他语言调用。
文件尺寸对比
bash
➜ my_lib git:(master) ✗ ll -lh target/debug
total 29624
drwxr-xr-x 2 thomas staff 64B Nov 3 02:00 build
drwxr-xr-x 37 thomas staff 1.2K Nov 3 02:07 deps
drwxr-xr-x 2 thomas staff 64B Nov 3 02:00 examples
drwxr-xr-x 6 thomas staff 192B Nov 3 02:07 incremental
-rw-r--r-- 1 thomas staff 14M Nov 3 02:07 libmy_lib.a
-rw-r--r-- 1 thomas staff 98B Nov 3 02:00 libmy_lib.d
-rwxr-xr-x 1 thomas staff 16K Nov 3 02:07 libmy_lib.dylib
-rw-r--r-- 1 thomas staff 5.6K Nov 3 02:07 libmy_lib.rlib
包管理工具Cargo
bash
cargo new my_project
bash
cargo run
bash
cargo check
bash
cargo build --release
bash
cargo clean
典型的包结构
bash
➜ firstrust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── benches # 基准性能测试
│ └── simple_bench.rs
├── examples # 项目示例
│ └── simple_example.rs
├── src # 源文件
│ ├── bin # 其余二进制包
│ │ ├── main1.rs
│ │ └── main2.rs
│ ├── lib.rs # 唯一库包
│ └── main.rs # 默认二进制包
└── tests # 集成测试
└── some_test.rs
6 directories, 9 files
➜ firstrust git:(master) ✗
多个入口函数,指定入口函数
bash
cargo run --bin main2
引用外部库
bash
cargo add rand
toml
[dependencies]
rand = "0.8.5"
rust
extern crate rand;
use rand::random;
fn main() {
for i in 0..10 {
let x = random::<i32>();
println!("{}: {}", i, x)
}
}
打开本地命令
rust
use std::process::Command;
fn main() {
Command::new("ls")
.args(&["-lh", "/usr"])
.status().unwrap();
}
模块
模块是项目中的代码组织方式,Rust使用 mod
关键字来定义模块。
rust
mod mymod {
pub fn foo() {
println!("foo");
}
}
fn main() {
mymod::foo();
}
rust
mod mymod {
pub fn foo() {
println!("foo");
}
}
use mymod::foo;
fn main() {
foo();
}
rust
mod mymod {
// 模块外不可见
pub const MSG: &'static str = "Hello";
// 模块内的字模块可见
pub(self) const MSG2: &'static str = "Hello2";
// 整个 crate 可见
pub(crate) const MSG3: &'static str = "Hello3";
pub mod inner {
pub fn foo() {
println!("foo {}", super::MSG2);
}
}
}
fn main() {
println!("{}", mymod::MSG);
mymod::inner::foo();
println!("{}", mymod::MSG3);
}