Rust 项目结构与分层
bin/lib 拆分、模块分层、依赖方向与中小型服务的推荐骨架。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust 项目结构与分层
这个概念为什么出现
能编译不等于可维护。
需要约定:入口、领域、接口适配器如何放,依赖只能单向。
[!abstract] 一句话理解 二进制保持瘦入口;核心逻辑放 library;按领域模块划分;外层依赖内层,避免循环与“utils 垃圾场”。
最小可运行示例
场景:订单服务骨架目录
order-service/
Cargo.toml
src/
main.rs # 组装与启动
lib.rs # 核心导出
domain/ # 实体与规则
mod.rs
order.rs
app/ # 用例服务
mod.rs
infra/ # 文件/HTTP/DB 适配
mod.rs
tests/
smoke.rs
main.rs 只做:读配置 → 构造服务 → 跑。
domain 不依赖 infra。
// 示意:领域纯函数不依赖框架
pub fn can_cancel(status: &str) -> bool {
status == "created" || status == "paid"
}
fn main() {
println!("cancel_allowed={}", can_cancel("paid"));
}
结合场景再看三个关注点
- 可测性:domain 无 IO
- 替换 infra 不影响规则
- workspace 可再拆 crate
核心概念与准确模型
- 依赖方向:
main → app → domain,infra →实现接口 - feature 开关可选能力
- examples/ 放可运行样例
- benches/ 放基准
设计动机
- 长期演进
- 测试金字塔可行
- 团队导航成本下降
边界与误区
- 过早微服务/过多 crate
- 循环 use
- 把框架类型漏进 domain
[!warning] 常见误区:所有代码塞 main.rs 两周后不可测。
工程实践
- 先单 crate 分层,再 workspace
- 公共 API 最小化
- README 画模块图
- lint 限制某些模块依赖(如 cargo-deny/layer 约定)
本节总结
- 瘦 bin 厚 lib
- 领域独立
- 依赖单向
自测题
- 为什么 domain 不该依赖具体 DB crate?
tests/放什么?
参考答案
- 便于替换与单测,避免基础设施细节污染规则。
- 面向公共 API 的集成/端到端级测试。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Cargo project layout | 官方 | 目录约定 |
| The Book — Packages | 官方书 | 组织 |