我们将讨论rust中的crates和modules的概念来帮助组织项目
crates
rust程序是由crates组成的,每个crate是单个库或可执行文件以及一些可选信息。
当使用cargo build --verbose
来构建时,可以看到依赖信息;我们也可以在Cargo.toml
中指定依赖的版本信息。
[dependencies]
num = "0.4"
当编译库rlib时,rust使用--crate-type lib
的选项;编译称二进制时,使用--crate-type bin
. 当rust程序依赖外部库时,通常会传递--extern
来告知外部库名称。当然这些并不需要显式指定。
当编译成release版本时,使用cargo build --release
,这将生成更高效的代码。
build profile
在Cargo.toml
中存在一些配置设置,影响rustc的命令行参数:
命令行 | cargo.toml section |
---|---|
cargo build | [profile.dev] |
cargo build --release | [profile.release] |
cargo test | [profile.test] |
为了更好地利用profiler,我们可能需要在release版本下,保留debug 的符号
[profile.release]
debug = true
modules
crates是项目之间的共享;而module是项目内的共享,作为rust的名字空间:
mod spores {use cell::{Cell, Gene};pub struct Spore {}pub(crate) fn test() {}
}
注意pub(crate)
意味着它可以在crate内的任何位置被访问,但并不作为外部接口导出。
嵌套modules
pub(super)
可以使得item只对parent module可见;pub(in <path>)
可以使得item对特定的parent及其后代可见,
将modules划分为多个文件
一个module也可以这样写,mod spores;
;这里我们是让rust去找这个spores存在的文件。注意rust不会分离地编译module,当重新build时,会重新编译所有的module。
考虑一个复杂的组织:
fern_sim/
|-- Cargo.toml
--- src/--- main.rs--- spores.rs--- plant/--- mod.rs--- leave.rs--- stems/--- ph.rs--- xy.rs--- stems.rs
我们可以在stems.rs 声明两个新的submodules:
pub mod ph;
pub mod xy;
路径和导入
use 类似于C++中的use
注意submodule不会自动继承父module的item,可以使用 use super::
来指定。
使用use ::image;
表示使用外部的image crate; 当前module也可以通过self
指定。
标准prelude
statics & consts
pub const PI: f64 = 3.14; // 类似 #definepub static PI: f64 = 3.14; // 可以被ref
把一个程序转为库
lib.rs
fern_sim/
--- cargo.toml
--- src/--- bin/--- rfern.rs
cargo run --bin rfern
可以编译对应的二进制文件。
Attributes
rust程序中的任何item都可以被attr修饰
条件编译:
#[cfg(target_os="android")]
mod mobile;
一些常用cfg:
option | 什么时候用 |
---|---|
test | test被开启时 |
debug_assertions | debug assert被开启时 |
unix | 只为unix系统编译,包括macos |
windows | |
target_pointer_width = "64" | 64 位 |
target_arch = "x86_64" | 面向x86_64 |
target_os = "macos" | |
feature = "robots" | 特定的feature |
not(A) | |
all(A, B) | |
any(A, B) |
考虑一种不会被自动内联的情况:当定义在一个crate的函数或方法被另一个crate调用时,除非是generic或是#[inline]
显式注解。
为了给整个crate标注属性,需要在开头使用#!
test
使用#[test]
进行标注
#[test]
fn math_test() {assert_eq!(0+1, 1);
}
可以使用debug_assert!
等,将不会在release模式下编译
为了测试失败的情况,应使用#[should_panic(expected="h")]
注意test只有在cargo test时才会编译;如果有很多代码,可以将其组织为test module,如下
#[cfg(test)]
mod tests {#[test]fn //
}
Workspace
当项目中存在多个crates,可以使用workspace的概念进行组织,例如在顶层目录新建一个Cargo.toml
:
[workspace]
members = ["fern_sim"]