rust-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Rust Patterns

Rust 惯用模式

Ownership-first, zero-cost abstractions, no hidden complexity.
以所有权为核心、零成本抽象、无隐藏复杂度。

Error Handling

错误处理

Always use
Result<T, E>
. Never panic for expected failures:
rust
// Use thiserror for library error types
#[derive(Debug, thiserror::Error)]
pub enum UserError {
    #[error("user not found: {0}")]
    NotFound(String),
    #[error("invalid email format")]
    InvalidEmail,
    #[error("database error: {0}")]
    Database(#[from] sqlx::Error),
}

// Use anyhow for applications (context chaining)
fn fetch_user(id: &str) -> anyhow::Result<User> {
    let user = db.get(id)
        .context("fetching user from database")?;
    Ok(user)
}
Propagate with
?
, add context at boundaries.
始终使用
Result<T, E>
。针对可预期的错误绝不要panic:
rust
// 为库错误类型使用thiserror
#[derive(Debug, thiserror::Error)]
pub enum UserError {
    #[error("user not found: {0}")]
    NotFound(String),
    #[error("invalid email format")]
    InvalidEmail,
    #[error("database error: {0}")]
    Database(#[from] sqlx::Error),
}

// 在应用中使用anyhow(上下文链式调用)
fn fetch_user(id: &str) -> anyhow::Result<User> {
    let user = db.get(id)
        .context("fetching user from database")?;
    Ok(user)
}
使用
?
传播错误,在边界处添加上下文信息。

Ownership Patterns

所有权模式

Borrowing > Cloning:
rust
// Good: Borrow for read-only
fn process(items: &[Item]) -> usize { ... }

// Good: Take ownership when storing/transforming
fn consume(items: Vec<Item>) -> Output { ... }

// Avoid: Excessive cloning
fn bad(items: &Vec<Item>) {
    let copy = items.clone(); // Usually unnecessary
}
Fight the borrow checker → redesign, don't circumvent.
优先使用借用而非克隆:
rust
// 推荐:只读场景使用借用
fn process(items: &[Item]) -> usize { ... }

// 推荐:存储或转换时获取所有权
fn consume(items: Vec<Item>) -> Output { ... }

// 避免:过度克隆
fn bad(items: &Vec<Item>) {
    let copy = items.clone(); // 通常并无必要
}
与其对抗借用检查器,不如重新设计代码,不要试图规避它。

Trait Design

Trait 设计

Small, focused traits (1-3 methods):
rust
trait Readable {
    type Item;
    fn read(&self) -> Self::Item;
}

trait Writable {
    type Item;
    fn write(&mut self, item: Self::Item);
}

// Compose through bounds
fn copy<R, W>(src: &R, dst: &mut W)
where
    R: Readable<Item = Vec<u8>>,
    W: Writable<Item = Vec<u8>>,
{ ... }
Consumer-side interfaces. Static dispatch by default.
设计小巧、职责单一的trait(1-3个方法):
rust
trait Readable {
    type Item;
    fn read(&self) -> Self::Item;
}

trait Writable {
    type Item;
    fn write(&mut self, item: Self::Item);
}

// 通过约束实现组合
fn copy<R, W>(src: &R, dst: &mut W)
where
    R: Readable<Item = Vec<u8>>,
    W: Writable<Item = Vec<u8>>,
{ ... }
面向消费者的接口。默认使用静态分发。

Configuration

配置

Cargo features for compile-time options:
toml
[features]
default = ["json"]
json = ["serde_json"]
database = ["sqlx"]
full = ["json", "database"]
rust
#[cfg(feature = "json")]
pub mod json_support { ... }
使用Cargo特性实现编译时配置:
toml
[features]
default = ["json"]
json = ["serde_json"]
database = ["sqlx"]
full = ["json", "database"]
rust
#[cfg(feature = "json")]
pub mod json_support { ... }

Unsafe

Unsafe 代码

Minimize. Document with
// SAFETY:
comments:
rust
// SAFETY: We verified ptr is non-null and properly aligned
// in the caller's bounds check above
unsafe { *ptr }
Abstract behind safe interfaces.
尽量减少使用。必须添加
// SAFETY:
注释说明:
rust
// SAFETY:我们已在调用方的边界检查中验证了ptr非空且对齐正确
unsafe { *ptr }
在安全接口背后封装unsafe代码。

Anti-Patterns

反模式

  • unwrap()
    /
    expect()
    for recoverable errors
  • Result<T, String>
    (use typed errors)
  • Excessive
    Rc<RefCell<T>>
    (redesign ownership)
  • Monolithic traits (10+ methods)
  • Reflection instead of generics
  • Fighting borrow checker with unsafe
  • 针对可恢复错误使用
    unwrap()
    /
    expect()
  • 使用
    Result<T, String>
    (应使用类型化错误)
  • 过度使用
    Rc<RefCell<T>>
    (应重新设计所有权)
  • 单体式trait(包含10个以上方法)
  • 使用反射而非泛型
  • 使用unsafe规避借用检查器