Communitygithub.com

rust-patterns

惯用的 Rust 模式、所有权、错误处理、trait、并发以及构建安全高性能应用的最佳实践。在编写或审查 Rust 代码,涉及所有权、错误处理、trait 或并发问题时使用。

rust-patterns 是什么?

该技能专注于 Rust 语言的核心模式与最佳实践,涵盖了所有权与借用、错误处理(Result、? 运算符、thiserror 与 anyhow)、枚举与模式匹配、trait 与泛型、并发(Arc<Mutex<T>>、通道、异步)以及模块系统等关键领域。其核心原则是“使非法状态不可表示”和“零成本抽象”,通过丰富的代码示例和反模式对比,帮助开发者编写安全、高性能且易于维护的 Rust 代码。主要面向使用 Rust 进行开发的工程师,适用于代码编写、审查、重构和设计决策等场景。技能支持 CLI 和 IDE 集成,通过提供即时的代码提示、规则检查和反模式警告来提升开发效率。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/rust-patterns

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Rust 开发模式

用于构建安全、高性能且易于维护的应用程序的惯用 Rust 模式和最佳实践。

何时使用

  • 编写新的 Rust 代码
  • 审查 Rust 代码
  • 重构现有的 Rust 代码
  • 设计 crate 结构和模块布局

工作原理

本技能在六个关键领域贯彻惯用的 Rust 约定:所有权与借用(在编译时防止数据竞争)、Result/? 错误传播(库使用 thiserror,应用使用 anyhow)、枚举与穷尽模式匹配(使非法状态不可表示)、trait 与泛型(零成本抽象)、安全的并发(通过 Arc<Mutex<T>>、通道和 async/await),以及按领域组织的最小 pub 接口。

核心原则

1. 所有权与借用

Rust 的所有权系统在编译时防止数据竞争和内存错误。

// 好:不需要所有权时传递引用
fn process(data: &[u8]) -> usize {
    data.len()
}

// 好:仅在需要存储或消费时获取所有权
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// 坏:为避免借用检查器而不必要地克隆
fn process_bad(data: &Vec<u8>) -> usize {
    let cloned = data.clone(); // 浪费——直接借用即可
    cloned.len()
}

使用 Cow 实现灵活的所有权

use std::borrow::Cow;

fn normalize(input: &str) -> Cow<'_, str> {
    if input.contains(' ') {
        Cow::Owned(input.replace(' ', "_"))
    } else {
        Cow::Borrowed(input) // 无需修改时零成本
    }
}

错误处理

使用 Result 和 ? —— 生产中绝不使用 unwrap()

// 好:传播错误并附带上下文
use anyhow::{Context, Result};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("从 {path} 读取配置失败"))?;
    let config: Config = toml::from_str(&content)
        .with_context(|| format!("从 {path} 解析配置失败"))?;
    Ok(config)
}

// 坏:错误时直接 panic
fn load_config_bad(path: &str) -> Config {
    let content = std::fs::read_to_string(path).unwrap(); // 会 panic!
    toml::from_str(&content).unwrap()
}

库错误用 thiserror,应用错误用 anyhow

// 库代码:结构化的、类型化的错误
use thiserror::Error;

#[derive(Debug, Error)]
pub enum StorageError {
    #[error("未找到记录: {id}")]
    NotFound { id: String },
    #[error("连接失败")]
    Connection(#[from] std::io::Error),
    #[error("无效数据: {0}")]
    InvalidData(String),
}

// 应用代码:灵活的错误处理
use anyhow::{bail, Result};

fn run() -> Result<()> {
    let config = load_config("app.toml")?;
    if config.workers == 0 {
        bail!("工作线程数必须大于 0");
    }
    Ok(())
}

使用 Option 的组合器而非嵌套匹配

// 好:组合器链
fn find_user_email(users: &[User], id: u64) -> Option<String> {
    users.iter()
        .find(|u| u.id == id)
        .map(|u| u.email.clone())
}

// 坏:深度嵌套的匹配
fn find_user_email_bad(users: &[User], id: u64) -> Option<String> {
    match users.iter().find(|u| u.id == id) {
        Some(user) => match &user.email {
            email => Some(email.clone()),
        },
        None => None,
    }
}

枚举与模式匹配

将状态建模为枚举

// 好:不可能的状态是不可表示的
enum ConnectionState {
    Disconnected,
    Connecting { attempt: u32 },
    Connected { session_id: String },
    Failed { reason: String, retries: u32 },
}

fn handle(state: &ConnectionState) {
    match state {
        ConnectionState::Disconnected => connect(),
        ConnectionState::Connecting { attempt } if *attempt > 3 => abort(),
        ConnectionState::Connecting { .. } => wait(),
        ConnectionState::Connected { session_id } => use_session(session_id),
        ConnectionState::Failed { retries, .. } if *retries < 5 => retry(),
        ConnectionState::Failed { reason, .. } => log_failure(reason),
    }
}

穷尽匹配 —— 业务逻辑中不要使用通配符

// 好:显式处理每个变体
match command {
    Command::Start => start_service(),
    Command::Stop => stop_service(),
    Command::Restart => restart_service(),
    // 添加新变体时,必须在此处处理
}

// 坏:通配符隐藏了新变体
match command {
    Command::Start => start_service(),
    _ => {} // 静默忽略了 Stop、Restart 以及未来的变体
}

Traits 与泛型

接受泛型,返回具体类型

// 好:泛型输入,具体输出
fn read_all(reader: &mut impl Read) -> std::io::Result<Vec<u8>> {
    let mut buf = Vec::new();
    reader.read_to_end(&mut buf)?;
    Ok(buf)
}

// 好:为多个约束使用 trait bound
fn process<T: Display + Send + 'static>(item: T) -> String {
    format!("已处理: {item}")
}

为动态分发使用 Trait 对象

// 当你需要异构集合或插件系统时使用
trait Handler: Send + Sync {
    fn handle(&self, request: &Request) -> Response;
}

struct Router {
    handlers: Vec<Box<dyn Handler>>,
}

// 当你需要性能时使用泛型(单态化)
fn fast_process<H: Handler>(handler: &H, request: &Request) -> Response {
    handler.handle(request)
}

新类型模式实现类型安全

// 好:不同的类型防止参数混淆
struct UserId(u64);
struct OrderId(u64);

fn get_order(user: UserId, order: OrderId) -> Result<Order> {
    // 不会意外交换用户和订单 ID
    todo!()
}

// 坏:容易交换参数
fn get_order_bad(user_id: u64, order_id: u64) -> Result<Order> {
    todo!()
}

结构体与数据建模

复杂构造的构建器模式

struct ServerConfig {
    host: String,
    port: u16,
    max_connections: usize,
}

impl ServerConfig {
    fn builder(host: impl Into<String>, port: u16) -> ServerConfigBuilder {
        ServerConfigBuilder { host: host.into(), port, max_connections: 100 }
    }
}

struct ServerConfigBuilder { host: String, port: u16, max_connections: usize }

impl ServerConfigBuilder {
    fn max_connections(mut self, n: usize) -> Self { self.max_connections = n; self }
    fn build(self) -> ServerConfig {
        ServerConfig { host: self.host, port: self.port, max_connections: self.max_connections }
    }
}

// 用法:ServerConfig::builder("localhost", 8080).max_connections(200).build()

迭代器与闭包

优先使用迭代器链而非手动循环

// 好:声明式、惰性、可组合
let active_emails: Vec<String> = users.iter()
    .filter(|u| u.is_active)
    .map(|u| u.email.clone())
    .collect();

// 坏:命令式累积
let mut active_emails = Vec::new();
for user in &users {
    if user.is_active {
        active_emails.push(user.email.clone());
    }
}

使用带类型注解的 collect()

// 收集到不同类型中
let names: Vec<_> = items.iter().map(|i| &i.name).collect();
let lookup: HashMap<_, _> = items.iter().map(|i| (i.id, i)).collect();
let combined: String = parts.iter().copied().collect();

// 收集 Results —— 在第一个错误时短路
let parsed: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse()).collect();

并发

共享可变状态使用 Arc<Mutex<T>>

use std::sync::{Arc, Mutex};

let counter = Arc::new(Mutex::new(0));
let handles: Vec<_> = (0..10).map(|_| {
    let counter = Arc::clone(&counter);
    std::thread::spawn(move || {
        let mut num = counter.lock().expect("mutex 被污染");
        *num += 1;
    })
}).collect();

for handle in handles {
    handle.join().expect("工作线程 panic");
}

消息传递使用通道

use std::sync::mpsc;

let (tx, rx) = mpsc::sync_channel(16); // 有界通道,带背压

for i in 0..5 {
    let tx = tx.clone();
    std::thread::spawn(move || {
        tx.send(format!("消息 {i}")).expect("接收端已断开");
    });
}
drop(tx); // 关闭发送端,以便 rx 迭代器终止

for msg in rx {
    println!("{msg}");
}

使用 Tokio 实现异步

use tokio::time::Duration;

async fn fetch_with_timeout(url: &str) -> Result<String> {
    let response = tokio::time::timeout(
        Duration::from_secs(5),
        reqwest::get(url),
    )
    .await
    .context("请求超时")?
    .context("请求失败")?;

    response.text().await.context("读取响应体失败")
}

// 生成并发任务
async fn fetch_all(urls: Vec<String>) -> Vec<Result<String>> {
    let handles: Vec<_> = urls.into_iter()
        .map(|url| tokio::spawn(async move {
            fetch_with_timeout(&url).await
        }))
        .collect();

    let mut results = Vec::with_capacity(handles.len());
    for handle in handles {
        results.push(handle.await.unwrap_or_else(|e| panic!("生成的任务 panic: {e}")));
    }
    results
}

不安全代码

何时可以接受不安全代码

// 可接受:FFI 边界,记录有不变式(Rust 2024+)
/// # Safety
/// `ptr` 必须是已初始化 `Widget` 的有效对齐指针。
unsafe fn widget_from_raw<'a>(ptr: *const Widget) -> &'a Widget {
    // SAFETY:调用者保证 ptr 有效且对齐
    unsafe { &*ptr }
}

// 可接受:性能关键路径,附有正确性证明
// SAFETY:由于循环边界,index 始终 < len
unsafe { slice.get_unchecked(index) }

何时 unsafe 是 NOT 可接受的

// 坏:使用 unsafe 绕过借用检查器
// 坏:为了方便使用 unsafe
// 坏:使用 unsafe 但未添加 Safety 注释
// 坏:在不相关类型之间进行 transmute

模块系统与 Crate 结构

按领域组织,而非按类型

my_app/
├── src/
│   ├── main.rs
│   ├── lib.rs
│   ├── auth/          # 领域模块
│   │   ├── mod.rs
│   │   ├── token.rs
│   │   └── middleware.rs
│   ├── orders/        # 领域模块
│   │   ├── mod.rs
│   │   ├── model.rs
│   │   └── service.rs
│   └── db/            # 基础设施
│       ├── mod.rs
│       └── pool.rs
├── tests/             # 集成测试
├── benches/           # 基准测试
└── Cargo.toml

可见性 —— 最小化暴露

// 好:使用 pub(crate) 进行内部共享
pub(crate) fn validate_input(input: &str) -> bool {
    !input.is_empty()
}

// 好:从 lib.rs 重新导出公共 API
pub mod auth;
pub use auth::AuthMiddleware;

// 坏:将所有内容设为 pub
pub fn internal_helper() {} // 应该是 pub(crate) 或私有

工具集成

基本命令

# 构建和检查
cargo build
cargo check              # 快速类型检查,不生成代码
cargo clippy             # lint 和建议
cargo fmt                # 格式化代码

# 测试
cargo test
cargo test -- --nocapture    # 显示 println 输出
cargo test --lib             # 仅单元测试
cargo test --test integration # 仅集成测试

# 依赖
cargo audit              # 安全审计
cargo tree               # 依赖树
cargo update             # 更新依赖

# 性能
cargo bench              # 运行基准测试

快速参考:Rust 惯用法

惯用法描述
借用,不要克隆除非需要所有权,否则传递 &T 而不是克隆
使非法状态不可表示使用枚举建模仅有效状态
? 优先于 unwrap()传播错误,在库/生产代码中绝不 panic
解析,不要验证在边界将非结构化数据转换为类型化结构体
新类型实现类型安全用新类型包装基本类型,防止参数交换
优先使用迭代器而非循环声明式链更清晰,通常也更快
在 Result 上使用 #[must_use]确保调用者处理返回值
Cow 实现灵活所有权在借用足够时避免分配
穷尽匹配在关键业务枚举中不使用通配符 _
最小的 pub 接口内部 API 使用 pub(crate)

应避免的反模式

// 坏:生产代码中使用 .unwrap()
let value = map.get("key").unwrap();

// 坏:为满足借用检查器而 .clone(),但不理解原因
let data = expensive_data.clone();
process(&original, &data);

// 坏:在 &str 足够时使用 String
fn greet(name: String) { /* 应该是 &str */ }

// 坏:在库中使用 Box<dyn Error>(应使用 thiserror)
fn parse(input: &str) -> Result<Data, Box<dyn std::error::Error>> { todo!() }

// 坏:忽略 must_use 警告
let _ = validate(input); // 静默丢弃了一个 Result

// 坏:在异步上下文中阻塞
async fn bad_async() {
    std::thread::sleep(Duration::from_secs(1)); // 阻塞执行器!
    // 使用:tokio::time::sleep(Duration::from_secs(1)).await;
}

请记住:如果编译通过,那么可能是正确的——但前提是你避免使用 unwrap(),尽可能减少 unsafe,并让类型系统为你工作。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

相关技能