npx skills add https://github.com/clementwalter/claudine --skill 'Senior Rust Practices'经过实战检验的 Rust 工作区架构、代码组织、依赖管理和测试模式,适用于从原型到生产的全阶段。
在完成任何 Rust 任务之前,你必须:
cargo test --workspace --release在以下情况时使用 Rust 工作区:
规范的工作区结构:
repo/
Cargo.toml # 工作区根目录
crates/
core/ # 纯领域逻辑(无 IO)
storage/ # 数据库、文件系统等
api/ # HTTP/GRPC 处理器、DTO
cli/ # 二进制文件
tools/ # 可选:内部二进制文件(代码生成、迁移等)
tests/ # 可选:黑盒集成测试
分层架构:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
关键规则: 如果 core 导入了 tokio、reqwest 或 sqlx,那么你已经失去了分离性。
过多的 crate 是徒劳的工作。开始时最多 2-5 个。
仅在以下情况拆分:
在根目录 Cargo.toml 中,使用工作区依赖来保持版本一致:
[workspace]
members = ["crates/*"]
resolver = "2"
[workspace.dependencies]
anyhow = "*" # 使用最新版本
thiserror = "*" # 使用最新版本
serde = { version = "*", features = ["derive"] } # 使用最新版本
tokio = { version = "*", features = ["macros", "rt-multi-thread"] } # 使用最新版本
在 crate 的 Cargo.toml 中:
[dependencies]
serde = { workspace = true }
这可以减少版本漂移和安全更新。
可选依赖的模式:
[dependencies]
sqlx = { workspace = true, optional = true }
[features]
db = ["dep:sqlx"]
rust-toolchain.toml 固定工具链按能力/领域组织,而非“models/handlers/utils”式的混乱结构。
良好的组织:
core/
src/
lib.rs
payment/
mod.rs
validation.rs
pricing.rs
user/
mod.rs
id.rs
rules.rs
避免:
models.rs
handlers.rs
utils.rs
默认将大多数内容设为 pub(crate)
从 lib.rs 重新导出一个精心设计的 API
mod payment; pub use payment::{Payment, PaymentError};
如果所有内容都是 pub,那么你无意中创建了一个框架。
Prelude 往往会隐藏依赖关系,使代码审查更加困难。优先使用显式导入。
常用方法:
thiserror 处理类型化错误anyhow除非你明确需要“不透明”的错误,否则不要在库边界泄漏 anyhow::Error。
如果能让核心保持同步和纯净,你将获得:
每个依赖都会增加:
优先选择维护良好的“稳定” crate。
cargo-deny + cargo-audit尽早发现依赖问题(许可证、安全公告、重复版本)。
unwrap()在二进制文件/测试中使用是可以的(尤其是在测试脚手架中)。在库中,应返回带有上下文的错误。
思考“金字塔”结构:
mod tests {} 以便访问私有内容使用 crates/<crate>/tests/*.rs 进行 API 级别的测试。
如果你有一个服务:
proptest 测试不变式(例如 decode(encode(x)) == x)cargo-fuzz 测试来自外部的解析器/解码器/输入文档测试确保示例能够编译,并保持公共 API 的真实性。如果你编写了文档测试,它们必须通过。永远不要忽略测试。
println! - 改用 Tracing永远不要使用 println!、eprintln! 或 dbg! 进行输出。 始终使用 tracing crate:
use tracing::{debug, info, warn, error, trace};
// 良好 - 结构化日志记录
info!("Processing request for user {user_id}");
debug!("Cache hit: {key}");
warn!("Retry attempt {attempt} of {max_retries}");
error!("Failed to connect: {err}");
// 糟糕 - 永远不要这样做
println!("Processing request for user {}", user_id);
dbg!(value);
原因:
test-log始终使用 test-log::test 属性来捕获测试中的追踪输出:
use test_log::test;
#[test]
fn test_something() {
info!("This will be visible when test fails or with --nocapture");
assert!(true);
}
#[test(tokio::test)]
async fn test_async_something() {
debug!("Async test with tracing");
}
添加到 Cargo.toml(使用最新版本):
[dev-dependencies]
test-log = { version = "*", features = ["trace"] } # 使用最新版本
tracing-subscriber = { version = "*", features = ["env-filter"] } # 使用最新版本
运行测试并显示日志:RUST_LOG=debug cargo test -- --nocapture
始终使用最严格的 clippy 规则。如果文件中未设置配置,请进行设置。
clippy::uninlined_format_args)始终在格式化字符串中直接使用变量,而不是将它们作为参数传递:
// 良好 - 变量内联
let name = "world";
info!("Hello, {name}!");
format!("Value: {value}, Count: {count}")
// 糟糕 - 未内联的参数
info!("Hello, {}!", name);
format!("Value: {}, Count: {}", value, count)
这提高了可读性,并减少了参数顺序错误的可能性。
cargo fmt --check
cargo clippy --all-targets --all-features -D warnings
cargo test --workspace --all-features
附加门禁:
cargo deny / cargo auditcargo llvm-cov 检查覆盖率,但不要盲目追求百分比resolver = "2",避免不必要的默认特性单向依赖:
core → (无)adapters → coreapp → adapters + corebin → app可见性:
IO 放置:
core 中进行 IO 操作测试分布:
工具链:
CLI: 精简的二进制文件 → 库(为了可测试性)
服务: 分离协议定义;使用特性标志控制传输层
ZK/加密: 隔离 no_std 核心;分离证明/验证 crate
WASM: 分离绑定;平台无关的核心
每周安装次数
0
仓库
GitHub 星标数
1
首次出现时间
1970年1月1日
安全审计
Battle-tested patterns for Rust workspace architecture, code organization, dependencies, and testing that scale from prototype to production.
Before completing ANY Rust task, you MUST:
cargo test --workspace --releaseUse a Rust workspace when you have:
Canonical workspace structure:
repo/
Cargo.toml # workspace root
crates/
core/ # pure domain logic (no IO)
storage/ # DB, filesystem, etc.
api/ # HTTP/GRPC handlers, DTOs
cli/ # binary
tools/ # optional: internal binaries (codegen, migration, etc.)
tests/ # optional: black-box integration tests
Layered architecture:
Critical rule: If core imports tokio, reqwest, or sqlx, you've already lost the separation.
Too many crates is busywork. Start with 2–5 max.
Split only when:
In root Cargo.toml, use workspace dependencies to keep versions aligned:
[workspace]
members = ["crates/*"]
resolver = "2"
[workspace.dependencies]
anyhow = "*" # use latest
thiserror = "*" # use latest
serde = { version = "*", features = ["derive"] } # use latest
tokio = { version = "*", features = ["macros", "rt-multi-thread"] } # use latest
In crate Cargo.toml:
[dependencies]
serde = { workspace = true }
This reduces version drift and security churn.
Pattern for optional dependencies:
[dependencies]
sqlx = { workspace = true, optional = true }
[features]
db = ["dep:sqlx"]
rust-toolchain.tomlOrganize by capability / domain, not by "models/handlers/utils" spaghetti.
Good organization:
core/
src/
lib.rs
payment/
mod.rs
validation.rs
pricing.rs
user/
mod.rs
id.rs
rules.rs
Avoid:
models.rs
handlers.rs
utils.rs
Make most things pub(crate) by default
Re-export a curated API from lib.rs
mod payment; pub use payment::{Payment, PaymentError};
If everything is pub you've created an accidental framework.
Preludes tend to hide dependencies and make code review harder. Prefer explicit imports.
Common approach:
thiserror for typed errorsanyhow at the top levelDon't leak anyhow::Error across library boundaries unless you explicitly want "opaque".
If you can keep core synchronous and pure, you gain:
Every dependency adds:
Prefer "boring" crates with strong maintenance.
cargo-deny + cargo-auditMake dependency issues visible early (licenses, advisories, duplicate versions).
unwrap() in LibrariesIn binaries/tests it's fine (especially in test scaffolding). In libraries, return errors with context.
Think "pyramid":
mod tests {} in the same file for private accessUse crates/<crate>/tests/*.rs for API-level tests.
If you have a service:
proptest for invariants ("decode(encode(x)) == x")cargo-fuzz for parsers/decoders/inputs from outsideDoctests enforce that examples compile and keep your public API honest. If you write doctests, they need to pass. Never ignore tests.
println! - Use Tracing InsteadNEVER useprintln!, eprintln!, or dbg! for output. Always use the tracing crate:
use tracing::{debug, info, warn, error, trace};
// Good - structured logging
info!("Processing request for user {user_id}");
debug!("Cache hit: {key}");
warn!("Retry attempt {attempt} of {max_retries}");
error!("Failed to connect: {err}");
// Bad - never do this
println!("Processing request for user {}", user_id);
dbg!(value);
Why:
test-log for TestsAlways use test_log::test attribute for tests to capture tracing output:
use test_log::test;
#[test]
fn test_something() {
info!("This will be visible when test fails or with --nocapture");
assert!(true);
}
#[test(tokio::test)]
async fn test_async_something() {
debug!("Async test with tracing");
}
Add to Cargo.toml (use latest versions):
[dev-dependencies]
test-log = { version = "*", features = ["trace"] } # use latest
tracing-subscriber = { version = "*", features = ["env-filter"] } # use latest
Run tests with visible logs: RUST_LOG=debug cargo test -- --nocapture
Always use the most pedantic clippy rules. If the config is not set in file, do it.
clippy::uninlined_format_args)Always use variables directly in format strings instead of passing them as arguments:
// Good - variable inlined
let name = "world";
info!("Hello, {name}!");
format!("Value: {value}, Count: {count}")
// Bad - uninlined arguments
info!("Hello, {}!", name);
format!("Value: {}, Count: {}", value, count)
This improves readability and reduces potential argument ordering mistakes.
cargo fmt --check
cargo clippy --all-targets --all-features -D warnings
cargo test --workspace --all-features
Additional gates:
cargo deny / cargo auditcargo llvm-cov for coverage, but don't worship %resolver = "2" and avoid unnecessary default featuresOne-way dependencies:
core → (nothing)adapters → coreapp → adapters + corebin → appVisibility:
IO placement:
coreTest distribution:
Tooling:
CLI: Thin binary → lib (for testability)
Services: Separate protocol definitions; feature-flag transport layers
ZK/crypto: Isolate no_std core; separate proving/verification crates
WASM: Separate bindings; platform-agnostic core
Weekly Installs
0
Repository
GitHub Stars
1
First Seen
Jan 1, 1970
Security Audits
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
103,800 周安装