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"));
}

结合场景再看三个关注点

  1. 可测性:domain 无 IO
  2. 替换 infra 不影响规则
  3. workspace 可再拆 crate

核心概念与准确模型

  • 依赖方向:main → app → domaininfra → 实现接口
  • feature 开关可选能力
  • examples/ 放可运行样例
  • benches/ 放基准

设计动机

  • 长期演进
  • 测试金字塔可行
  • 团队导航成本下降

边界与误区

  • 过早微服务/过多 crate
  • 循环 use
  • 把框架类型漏进 domain

[!warning] 常见误区:所有代码塞 main.rs 两周后不可测。

工程实践

  1. 先单 crate 分层,再 workspace
  2. 公共 API 最小化
  3. README 画模块图
  4. lint 限制某些模块依赖(如 cargo-deny/layer 约定)

本节总结

  • 瘦 bin 厚 lib
  • 领域独立
  • 依赖单向

自测题

  1. 为什么 domain 不该依赖具体 DB crate?
  2. tests/ 放什么?
参考答案
  1. 便于替换与单测,避免基础设施细节污染规则。
  2. 面向公共 API 的集成/端到端级测试。

延伸阅读与资料来源

资料类型支撑内容
Cargo project layout官方目录约定
The Book — Packages官方书组织
创建于 2026/7/15 更新于 2026/7/15