Skip to content

Rust 开发指南

引言

OneArchive 后端采用 Rust 语言开发,以获得高性能、内存安全和并发优势。本指南提供 Rust 开发环境配置、常用工具使用,以及项目遵循的代码规范和最佳实践。

1. 环境配置

1.1. 安装 Rust

使用 rustup(Rust 官方工具链管理器)安装:

bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装完成后,确保 Rust 添加到 PATH 环境变量。

1.2. 更新工具链

保持 Rust 工具链为最新稳定版本:

bash
rustup update stable
rustup default stable

1.3. 安装内置组件

安装 Rust 官方格式化工具和 Lint 工具:

bash
rustup component add rustfmt
rustup component add clippy

2. 常用 Cargo 工具

推荐安装以下 Cargo 工具,提升开发体验:

bash
cargo install cargo-edit        # cargo add/remove/update
cargo install cargo-watch       # 文件变动自动 check/test
cargo install cargo-expand      # 展开宏
cargo install cargo-outdated    # 检查过时依赖
cargo install cargo-audit       # 检查安全漏洞
cargo install cargo-udeps --locked  # 检查未使用依赖
cargo install cargo-tarpaulin   # 代码覆盖率

3. 工具使用场景

3.1. 日常开发

  • 代码格式化:使用 cargo fmt 确保代码风格一致。
  • 静态分析:使用 cargo clippy 发现潜在问题和改进点。
  • 依赖管理:使用 cargo-editcargo add/remove/update)简化依赖管理。
  • 开发监控:使用 cargo watch -x checkcargo watch -x test 在文件变更时自动检查或测试。

3.2. 调试与分析

  • 宏展开:使用 cargo expand 查看宏展开后的代码,便于调试复杂的宏。
  • 依赖检查:使用 cargo outdated 检查过时依赖,cargo udeps 检查未使用依赖。
  • 安全审计:使用 cargo audit 检查依赖中的已知安全漏洞。

3.3. 测试与覆盖率

  • 代码覆盖率:使用 cargo tarpaulin 生成代码覆盖率报告:

    bash
    cargo tarpaulin --out Html

    生成 HTML 格式覆盖率报告,位于 tarpaulin-report.html

4. 代码规范

4.1. 模块组织

采用 Rust 2018+ 模块系统,不再使用 mod.rs

模块 foo 定义在 src/foo.rs,其子模块 foo::bar 定义在 src/foo/bar.rs

避免将所有逻辑塞入单个 .rs 文件;文件过大时,拆分为多个逻辑子模块。

4.2. 子模块命名规范

所有子模块文件使用统一前缀格式:

  • api_: 接口定义。
  • impl_: 具体实现代码(结构体 impl、函数实现)。
  • trait_: Trait 定义。
  • model_: 数据模型、结构体、枚举定义。
  • utils_: 工具函数、辅助代码。
  • schema_: 数据库 schema 定义。
  • constants_: 常量定义。
  • common_: 通用代码、共享逻辑。
  • dao_: DAO 层实现。
  • core_: 核心逻辑。
  • service_: 服务层实现。

通用顶级模块使用 api,非通用顶级模块保持 mod_ 前缀,子模块统一使用上述前缀。目录下文件遵循相同规则,避免无前缀或混合命名。

4.3. 测试文件命名规范

测试文件(位于 tests/ 目录下的集成测试)统一使用 test_ 前缀,如 test_archive.rstest_database.rs

这是 Rust 标准约定,Cargo 自动识别并运行,无需额外配置。测试代码中的模块引用与源码一致,确保路径更新同步。

4.4. 函数与结构

  • 单个函数体(不含注释和空行)不应超过 50 行。理想长度 25 行以内。
  • 公共逻辑提取到独立模块(如 utils.rserror.rs)。
  • 优先使用 ResultOption 进行错误和空值处理,避免 panic。
  • 结构体和枚举合理拆分,避免"上帝对象"。
  • 可以添加 log debug、info 等辅助排查问题,或修改错误暴露方式以排查 bug。

4.5. 代码风格

遵循 Rust 官方代码风格指南。

使用 cargo fmt 作为格式化标准。

避免使用 unwrap()expect(),使用适当错误处理。

所有公开 API 必须有文档注释(///)。

避免不必要的 clone(),优先使用引用或 Cow

注释重要,但不要大篇幅添加注释。

5. 错误处理

使用 thiserror crate 定义自定义错误类型。

避免使用 anyhow 进行泛化错误处理,除非在顶层入口点。

6. 数据库抽象层实现

6.1. 统一错误类型

rust
#[derive(Debug)]
pub enum DatabaseError {
    Rusqlite(rusqlite::Error),
    #[cfg(feature = "sqlx")]
    Sqlx(sqlx::Error),
    // ... 其他数据库错误
    Custom(String),
}

6.2. Repository Trait

rust
pub trait ArchiveRepository {
    fn find_by_id(&self, id: i64) -> Result<Option<Archive>, DatabaseError>;
    fn save(&self, archive: &Archive) -> Result<(), DatabaseError>;
}

6.3. 具体实现

rust
pub struct RusqliteArchiveRepository {
    conn: Arc<Connection>,
}

impl ArchiveRepository for RusqliteArchiveRepository {
    // ... 实现
}

6.4. 实现与组织

  • 接口定义:在 src/db/ 目录下定义所有 trait。
  • 具体实现:为每种数据库创建独立的模块,如 src/db/rusqlite_impl/
  • 依赖注入:服务层通过泛型参数接收 Repository 实例,优先使用泛型以获得更好性能。

6.5. 禁止事项

  • 禁止在业务逻辑中直接使用具体数据库 API。
  • 禁止在 trait 方法签名中使用具体数据库类型。
  • 禁止在没有 feature gate 的情况下引入可选依赖。

7. 参考资源