stand-rust

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rust Standards

Rust编码规范

Standards for Rust code.
Rust代码编写规范。

Edition

版本选择

  • Use the latest stable edition (2021+)
  • Set
    edition
    explicitly in
    Cargo.toml
  • 使用最新稳定版本(2021+)
  • Cargo.toml
    中显式设置
    edition

Toolchain

工具链

  • Follow the
    lint
    skill for formatting and linting — lintro runs
    rustfmt
    ,
    clippy
    ,
    cargo_audit
    , and
    cargo_deny
    as configured
  • Treat clippy warnings as errors in CI (
    -D warnings
    )
  • Customize formatting via
    rustfmt.toml
    where needed
  • 遵循
    lint
    技能进行格式化与代码检查 — lintro会按照配置运行
    rustfmt
    clippy
    cargo_audit
    cargo_deny
  • 在CI中将clippy警告视为错误(
    -D warnings
  • 必要时通过
    rustfmt.toml
    自定义格式化规则

Error Handling

错误处理

  • Use
    thiserror
    for library error types — derive structured, typed errors
  • Use
    anyhow
    for application-level error propagation
  • No
    .unwrap()
    in library code — use
    ?
    or return
    Result
  • .expect()
    only with descriptive messages explaining the invariant:
    rust
    // Good
    let config = load_config().expect("config.toml must exist at startup");
    
    // Bad
    let config = load_config().unwrap();
  • Implement
    std::fmt::Display
    for all custom error types
  • Non-panicking
    .unwrap_or_default()
    /
    .unwrap_or()
    over trivial-arm matches:
    rust
    // Don't
    let count = match maybe_count {
        Some(n) => n,
        None => 0,
    };
    
    // Do
    let count = maybe_count.unwrap_or(0);
  • 为库错误类型使用
    thiserror
    — 派生结构化的类型化错误
  • 在应用层错误传播中使用
    anyhow
  • 库代码中禁止使用
    .unwrap()
    — 使用
    ?
    或返回
    Result
  • 仅在带有描述不变量的说明性消息时使用
    .expect()
    rust
    // Good
    let config = load_config().expect("config.toml must exist at startup");
    
    // Bad
    let config = load_config().unwrap();
  • 为所有自定义错误类型实现
    std::fmt::Display
  • 对于简单分支匹配,优先使用非panic的
    .unwrap_or_default()
    /
    .unwrap_or()
    rust
    // Don't
    let count = match maybe_count {
        Some(n) => n,
        None => 0,
    };
    
    // Do
    let count = maybe_count.unwrap_or(0);

Type Patterns

类型模式

  • Prefer newtypes for domain concepts —
    struct UserId(u64)
    over bare
    u64
  • Use
    impl Trait
    in argument position for flexibility; explicit generics in return position for clarity
  • Derive
    Debug
    on all public types
  • Derive
    Clone
    ,
    PartialEq
    ,
    Eq
    ,
    Hash
    where semantically appropriate
  • Prefer
    &str
    over
    String
    in function arguments; return
    String
    when ownership transfers
  • 优先为领域概念使用新类型 — 用
    struct UserId(u64)
    替代裸
    u64
  • 参数位置使用
    impl Trait
    以提升灵活性;返回位置使用显式泛型以保证清晰性
  • 为所有公共类型派生
    Debug
  • 在语义合适的情况下派生
    Clone
    PartialEq
    Eq
    Hash
  • 函数参数中优先使用
    &str
    而非
    String
    ;当需要转移所有权时返回
    String

Unsafe

Unsafe使用准则

  • unsafe
    blocks MUST include a
    // SAFETY:
    comment justifying soundness:
    rust
    // SAFETY: pointer is guaranteed non-null by the allocator contract,
    // and the lifetime is bounded by the enclosing scope.
    unsafe { ptr.as_ref() }
  • Minimize unsafe surface area — encapsulate in safe abstractions
  • Prefer safe alternatives (e.g.,
    std::sync::Mutex
    over raw atomics) unless performance demands otherwise
  • unsafe
    代码块必须包含
    // SAFETY:
    注释以说明安全性依据:
    rust
    // SAFETY: pointer is guaranteed non-null by the allocator contract,
    // and the lifetime is bounded by the enclosing scope.
    unsafe { ptr.as_ref() }
  • 最小化unsafe代码范围 — 将其封装在安全抽象中
  • 优先使用安全替代方案(例如
    std::sync::Mutex
    而非原始原子操作),除非性能要求必须使用unsafe

Documentation

文档编写

  • ///
    doc comments on all public items (functions, types, traits, modules)
  • Include code examples in doc comments for non-trivial APIs:
    rust
    /// Parse a duration string like "5s", "100ms", or "2m".
    ///
    /// # Examples
    ///
    /// ```
    /// use mycrate::parse_duration;
    ///
    /// let d = parse_duration("5s").unwrap();
    /// assert_eq!(d, std::time::Duration::from_secs(5));
    /// ```
    pub fn parse_duration(s: &str) -> Result<Duration> { ... }
  • Use
    #![deny(missing_docs)]
    for library crates
  • Module-level
    //!
    doc comments for crate and module overviews
  • 为所有公共项(函数、类型、trait、模块)添加
    ///
    文档注释
  • 为非简单API在文档注释中包含代码示例:
    rust
    /// Parse a duration string like "5s", "100ms", or "2m".
    ///
    /// # Examples
    ///
    /// ```
    /// use mycrate::parse_duration;
    ///
    /// let d = parse_duration("5s").unwrap();
    /// assert_eq!(d, std::time::Duration::from_secs(5));
    /// ```
    pub fn parse_duration(s: &str) -> Result<Duration> { ... }
  • 库crate使用
    #![deny(missing_docs)]
  • 为crate和模块概述添加模块级
    //!
    文档注释

Testing

测试规范

  • Unit tests in
    #[cfg(test)] mod tests
    within the same file
  • Integration tests in
    tests/
    directory
  • Use
    #[should_panic(expected = "...")]
    for expected panics
  • Consider
    proptest
    or
    quickcheck
    for property-based testing where valuable
  • Use
    assert_eq!
    and
    assert_ne!
    over bare
    assert!
    for better error messages
rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_duration_seconds() {
        let d = parse_duration("5s").unwrap();
        assert_eq!(d, Duration::from_secs(5));
    }

    #[test]
    #[should_panic(expected = "invalid format")]
    fn parse_duration_rejects_garbage() {
        parse_duration("not_a_duration").unwrap();
    }
}
  • 单元测试放在同一文件内的
    #[cfg(test)] mod tests
  • 集成测试放在
    tests/
    目录下
  • 对预期的panic使用
    #[should_panic(expected = "...")]
  • 在有价值的场景下考虑使用
    proptest
    quickcheck
    进行基于属性的测试
  • 优先使用
    assert_eq!
    assert_ne!
    而非裸
    assert!
    以获得更友好的错误信息
rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_duration_seconds() {
        let d = parse_duration("5s").unwrap();
        assert_eq!(d, Duration::from_secs(5));
    }

    #[test]
    #[should_panic(expected = "invalid format")]
    fn parse_duration_rejects_garbage() {
        parse_duration("not_a_duration").unwrap();
    }
}

Dependencies

依赖管理

  • Keep the dependency tree minimal — every dependency is an audit and supply chain surface
  • Run vulnerability scanning via lintro (
    uv run lintro chk
    includes
    cargo_audit
    and
    cargo_deny
    )
  • Pin versions in workspace
    Cargo.toml
    for multi-crate workspaces
  • Prefer well-maintained crates with active maintainers and good documentation
  • 保持依赖树最小化 — 每个依赖都会增加审计和供应链风险
  • 通过lintro运行漏洞扫描(
    uv run lintro chk
    包含
    cargo_audit
    cargo_deny
  • 多crate工作区在工作区
    Cargo.toml
    中固定版本
  • 优先选择维护良好、有活跃维护者且文档完善的crate

Patterns

编码模式

  • Prefer
    impl
    blocks over free functions for associated behavior
  • Use the builder pattern for types with many optional fields
  • Prefer iterators and combinators over manual loops where readability permits
  • let-else
    over nested
    if let
    pyramids:
    rust
    // Don't
    if let Some(user) = lookup(id) {
        if let Some(email) = user.email {
            send(email);
        }
    }
    
    // Do
    let Some(user) = lookup(id) else { return };
    let Some(email) = user.email else { return };
    send(email);
  • .find()
    /
    .position()
    /
    .any()
    over manual index loops:
    rust
    // Don't
    let mut idx = None;
    for (i, item) in items.iter().enumerate() {
        if item.id == target {
            idx = Some(i);
            break;
        }
    }
    
    // Do
    let idx = items.iter().position(|item| item.id == target);
  • matches!()
    for pattern booleans:
    rust
    // Don't
    let is_ready = match state {
        State::Ready => true,
        _ => false,
    };
    
    // Do
    let is_ready = matches!(state, State::Ready);
  • Use
    #[must_use]
    on functions whose return value should not be ignored
  • Prefer
    From
    /
    Into
    implementations over ad-hoc conversion methods
  • 优先使用
    impl
    块而非自由函数来实现关联行为
  • 为具有多个可选字段的类型使用构建器模式
  • 在可读性允许的情况下,优先使用迭代器和组合子而非手动循环
  • 使用
    let-else
    替代嵌套的
    if let
    金字塔:
    rust
    // Don't
    if let Some(user) = lookup(id) {
        if let Some(email) = user.email {
            send(email);
        }
    }
    
    // Do
    let Some(user) = lookup(id) else { return };
    let Some(email) = user.email else { return };
    send(email);
  • 使用
    .find()
    /
    .position()
    /
    .any()
    替代手动索引循环:
    rust
    // Don't
    let mut idx = None;
    for (i, item) in items.iter().enumerate() {
        if item.id == target {
            idx = Some(i);
            break;
        }
    }
    
    // Do
    let idx = items.iter().position(|item| item.id == target);
  • 使用
    matches!()
    进行模式布尔判断:
    rust
    // Don't
    let is_ready = match state {
        State::Ready => true,
        _ => false,
    };
    
    // Do
    let is_ready = matches!(state, State::Ready);
  • 对返回值不应被忽略的函数使用
    #[must_use]
  • 优先使用
    From
    /
    Into
    实现而非临时转换方法

Linting

代码检查

Follow the
lint
skill for linting and formatting workflow.
遵循
lint
技能进行代码检查与格式化工作流。