Communitygithub.com

rust-patterns

慣用的 Rust 模式:所有權、錯誤處理、trait、並發與建構安全、高效應用程式的最佳實踐。當撰寫或審查涉及所有權、錯誤處理、trait 或並發的 Rust 程式碼時使用。

rust-patterns 是什麼?

此技能強制執行六個關鍵領域的慣用 Rust 慣例:透過所有權與借用系統在編譯期防止資料競爭;使用 `thiserror`(函式庫)與 `anyhow`(應用程式)進行 `Result`/`?` 錯誤傳播;利用枚舉與窮舉模式匹配使非法狀態無法表示;透過 trait 與泛型實現零成本抽象;使用 `Arc<Mutex<T>>`、通道(channel)與 async/await 達成安全並發;以及按領域組織的最小公開(`pub`)介面。它特別適合在開發 Rust 專案時作為即時的風格指引,支援所有 Rust 編輯器與 CLI 工具(如 claude code、cursor、codex),透過提供可立即套用的程式碼片段與實戰反模式來運作。技能內含詳細的「何時使用」指引、核心原則說明、可複製的程式碼範例以及一個快速參考慣用語表,幫助開發者寫出更安全、效能更好且更易維護的 Rust 程式碼。

相容平台~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 慣例:透過所有權與借用系統在編譯期防止資料競爭;使用 thiserror(函式庫)與 anyhow(應用程式)進行 Result/? 錯誤傳播;利用枚舉與窮舉模式匹配使非法狀態無法表示;透過 trait 與泛型實現零成本抽象;使用 Arc<Mutex<T>>、通道(channel)與 async/await 達成安全並發;以及按領域組織的最小公開(pub)介面。

核心原則

1. 所有權與借用

Rust 的所有權系統在編譯期防止資料競爭與記憶體錯誤。

// 良好:不需要所有權時傳遞引用
fn process(data: &[u8]) -> usize {
    data.len()
}

// 良好:僅在需要儲存或消費時取得所有權
fn store(data: Vec<u8>) -> Record {
    Record { payload: data }
}

// 不良:為了繞過借用檢查器而進行不必要的 clone
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(); // 恐慌!
    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!("worker 數量必須大於 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 邊界
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> {
    // 不可能意外交換 user 和 order 的 ID
    todo!()
}

// 不良:容易交換參數
fn get_order_bad(user_id: u64, order_id: u64) -> Result<Order> {
    todo!()
}

結構體與資料建模

用於複雜建構的 Builder 模式

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("工作執行緒恐慌");
}

使用通道進行訊息傳遞

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!("產生的任務恐慌: {e}")));
    }
    results
}

不安全程式碼

何時可以接受 Unsafe

// 可接受:帶有已記錄不變量的 FFI 邊界 (Rust 2024+)
/// # 安全性
/// `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

// 不良:使用 unsafe 繞過借用檢查器
// 不良:為了方便而使用 unsafe
// 不良:使用 unsafe 但沒有安全性註解
// 不良:在不同型別之間進行 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             # 提示與建議
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()傳播錯誤,切勿在函式庫/生產程式碼中恐慌
解析,不要驗證在邊界處將非結構化資料轉換為型別化結構體
新類型確保型別安全將基本型別包裝在新類型中以防止參數交換
優先使用迭代器而非迴圈宣告式鏈更清晰,且通常更快
在 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.

相關技能