附录 D · Cargo / Clippy 速查

命令与配置的快速参考

核心问题:Cargo 常用命令与 Clippy lint 一览。

放手边,需要时翻。


D.1 cargo 基础命令

# 项目
cargo new my-app                # 新建 binary
cargo new --lib my-lib          # 新建 library
cargo init                      # 在当前目录初始化

# 编译
cargo check                     # 只检查类型,不生成 binary(快)
cargo build                     # debug build
cargo build --release           # release build,优化开启
cargo build --target x86_64-unknown-linux-musl   # 交叉编译

# 运行
cargo run                       # 跑 default binary
cargo run --bin server          # 跑指定 binary
cargo run --example foo         # 跑 examples/foo.rs
cargo run --release             # release 跑
cargo run -- --port 8080        # 把参数传给程序(-- 后)

# 测试
cargo test                      # 跑全部
cargo test some_test_name       # 跑匹配名字的测试
cargo test --lib                # 只 src/ 单元测试
cargo test --tests              # 只 tests/ 集成测试
cargo test --doc                # 只 doc-test
cargo test -- --nocapture       # 显示 println!
cargo test -- --test-threads=1  # 串行(适合改全局状态的测试)

# 格式化 + lint
cargo fmt                       # 格式化
cargo fmt --check               # 检查是否已格式化(CI 用)
cargo clippy                    # lint
cargo clippy --fix              # 自动修复部分
cargo clippy -- -D warnings     # 警告变错误

# 文档
cargo doc                       # 生成 target/doc/...
cargo doc --open                # 打开浏览器
cargo doc --no-deps             # 不生成依赖文档(快)

# 依赖
cargo update                    # 更新 Cargo.lock
cargo update -p tokio --precise 1.40.0   # 锁定具体版本
cargo tree                      # 看依赖树
cargo tree -d                   # 重复依赖检查

D.2 cargo 高级命令(常装的子命令)

# 安装
cargo install cargo-edit cargo-expand cargo-watch cargo-nextest

# cargo-edit
cargo add tokio --features full           # 加依赖
cargo add tokio@1                          # 指定版本
cargo rm serde                             # 移除
cargo upgrade                              # 升级所有依赖到 latest

# cargo-expand:看宏 / async 展开
cargo expand --bin myapp
cargo expand --lib path::module
cargo expand --tests test_name

# cargo-watch:文件改动自动跑命令
cargo watch -x check
cargo watch -x 'test some_test -- --nocapture'

# cargo-nextest:更快的 test runner
cargo nextest run

# 二进制体积分析
cargo install cargo-bloat
cargo bloat --release             # 看哪些函数最大
cargo bloat --release --crates    # 看哪个 crate 最大

# 未使用依赖
cargo install cargo-udeps
cargo +nightly udeps              # 找出 [dependencies] 里没用上的

# 过期依赖
cargo install cargo-outdated
cargo outdated

# 安全 / license 审计
cargo install cargo-audit cargo-deny
cargo audit
cargo deny check

# 覆盖率
cargo install cargo-llvm-cov
cargo llvm-cov --html

# 模糊测试
cargo install cargo-fuzz
cargo fuzz init
cargo fuzz run target_name

D.3 常用 Cargo.toml 配置

dependency 写法

[dependencies]
tokio = "1"                                          # 最新 1.x
tokio = { version = "1.40", features = ["full"] }    # 指定特性
local-lib = { path = "../local-lib" }                # 本地
git-lib = { git = "https://github.com/x/y.git", branch = "main" }
git-lib = { git = "https://...", tag = "v0.1" }
git-lib = { git = "https://...", rev = "abcdef" }    # 锁 commit
foo = { version = "1", default-features = false, features = ["bar"] }
foo = { version = "1", optional = true }             # feature 才启用

profile

[profile.release]
opt-level = 3                # 0-3 / "s" / "z" (size)
lto = "thin"                 # "fat" / "thin" / false
codegen-units = 1            # 1 最优,默认 16
strip = "symbols"            # 减小二进制
debug = false                # 不加 debug info
panic = "abort"              # 不展开栈(更小)
overflow-checks = false

[profile.dev]
opt-level = 1                # dev build 也开一点优化
debug = "line-tables-only"   # 调用栈够用,体积更小
incremental = true

[profile.bench]
debug = true                 # 让 flamegraph 看得见名字

[profile.release-with-debug]   # 自定义 profile
inherits = "release"
debug = true
strip = "none"

feature 写法

[features]
default = ["pg", "tls"]
pg = ["dep:sqlx-postgres"]
mysql = ["dep:sqlx-mysql"]
tls = ["dep:rustls", "dep:rustls-pemfile"]
unstable = []                # 仅启用 #[cfg(feature = "unstable")] 代码块

[dependencies]
sqlx-postgres = { version = "0.8", optional = true }
sqlx-mysql    = { version = "0.8", optional = true }
rustls        = { version = "0.23", optional = true }
rustls-pemfile= { version = "2", optional = true }

镜像 / 私有源

# .cargo/config.toml
[source.crates-io]
replace-with = "ustc"

[source.ustc]
registry = "https://mirrors.ustc.edu.cn/crates.io-index"

# 私有源
[registries.my-corp]
index = "ssh://git@host/my-registry"

workspace

[workspace]
members = ["crates/*"]
resolver = "2"

[workspace.package]
version = "0.1.0"
edition = "2021"

[workspace.dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

[patch] 覆盖依赖

[patch.crates-io]
serde = { git = "https://github.com/serde-rs/serde", branch = "main" }

D.4 Clippy 常见 lint

按类别(clippy::category):

clippy::correctness(默认 deny)

Lint含义
clippy::approx_constant用了近似常量(0.999... 而非 std::f64::consts::PI)
clippy::wrong_self_conventionto_x 应该 &self,into_x 应该 self
clippy::eq_opx == x 永远 true
clippy::erasing_opx * 0 之类

clippy::style

Lint含义
clippy::needless_returnreturn x; 在末尾(应该 x)
clippy::collapsible_ifif a { if b { ... } } 可合并
clippy::redundant_field_namesFoo { x: x } 可写 Foo { x }
clippy::let_and_returnlet x = ...; x 可直接 ...
clippy::single_matchmatch x { A => ..., _ => () } 用 if let

clippy::complexity

Lint含义
clippy::needless_borrow&&x 多余
clippy::unnecessary_unwrapif x.is_some() { x.unwrap() } 用 if let
clippy::useless_conversionString::from(s.to_string()) 多余
clippy::map_unwrap_or.map(...).unwrap_or(...) 用 .map_or(...)

clippy::perf

Lint含义
clippy::redundant_cloneclone 多余
clippy::large_enum_variantenum 一个变体远大于其他(浪费内存)
clippy::format_in_format_argsformat!("{}", format!(...)) 嵌套
clippy::useless_vec&vec![1, 2, 3] 应该 &[1, 2, 3]

clippy::pedantic(默认不开)

更严格,可选开。生产 crate 推荐:

#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]   // 觉得太烦的关掉

整 crate 配置

// crate root
#![warn(clippy::all, clippy::pedantic)]
#![warn(missing_docs)]
#![deny(unsafe_code)]      // 整个 crate 禁 unsafe
#![forbid(unsafe_code)]    // 更严:连 #[allow] 也覆盖不了

D.5 rustfmt 配置(rustfmt.toml)

# 行宽
max_width = 100

# import 整理
imports_granularity = "Crate"   # 把 use 按 crate 合并
group_imports = "StdExternalCrate"
reorder_imports = true

# 字符串 / 数组格式
use_field_init_shorthand = true
use_try_shorthand = true

# 调用链
chain_width = 80
fn_call_width = 80

# 注释
wrap_comments = true
comment_width = 100
normalize_comments = true

# 函数参数
fn_params_layout = "Tall"

# trailing comma
trailing_comma = "Vertical"

# 把 fn body 短的并到一行
fn_single_line = false

unstable_features = true 后能用更多选项,但需要 nightly rustfmt。


常用 CI 套路

- run: cargo fmt --check
- run: cargo clippy --all-targets --all-features -- -D warnings
- run: cargo test --all-features
- run: cargo audit
- run: cargo deny check

任何 PR 都过这五关 → 代码质量底线有了。


📝 学习记录

项内容
起始日期
完成日期
卡点
关键收获
配套代码仓库链接