rust-best-practices

rust-best-practices

根據 Apollo GraphQL 的最佳實務手冊,撰寫符合 Rust 慣用寫法的程式碼。適用於以下情況:(1) 撰寫新的 Rust 程式碼或函式;(2) 審查或重構現有 Rust 程式碼;(3) 決定借用 vs 複製或所有權模式;(4) 使用 Result 型別實作錯誤處理;(5) 最佳化 Rust 程式碼效能;(6) 為 Rust 專案撰寫測試或文件。

90星標
10分支
更新於 2026/6/4
SKILL.md
readonlyread-only
name
rust-best-practices
description

Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook. Use this skill when: (1) writing new Rust code or functions, (2) reviewing or refactoring existing Rust code, (3) deciding between borrowing vs cloning or ownership patterns, (4) implementing error handling with Result types, (5) optimizing Rust code for performance, (6) writing tests or documentation for Rust projects.

Rust 最佳實務

撰寫或審查 Rust 程式碼時,請遵循以下準則。本指南基於 Apollo GraphQL 的 Rust 最佳實務手冊

最佳實務參考

在審查之前,請先熟悉 Apollo 的 Rust 最佳實務。請在同一輪中平行閱讀所有相關章節。提供意見回饋時,請參考以下檔案:

快速參考

借用與所有權

  • 除非需要轉移所有權,否則優先使用 &T 而非 .clone()
  • 函式參數優先使用 &str 而非 String&[T] 而非 Vec<T>
  • 小型 Copy 型別(≤24 位元組)可以傳值
  • 當所有權不明確時,使用 Cow<'_, T>

錯誤處理

  • 可能失敗的操作回傳 Result<T, E>;避免在正式環境中使用 panic!
  • 絕不在測試以外的程式碼中使用 unwrap()/expect()
  • 函式庫錯誤使用 thiserror,僅二進位檔使用 anyhow
  • 錯誤傳播優先使用 ? 運算子而非 match 鏈

效能

  • 務必使用 --release 旗標進行基準測試
  • 執行 cargo clippy -- -D clippy::perf 取得效能提示
  • 避免在迴圈中複製;對 Copy 型別使用 .iter() 而非 .into_iter()
  • 優先使用迭代器而非手動迴圈;避免中間的 .collect() 呼叫

Linting

定期執行:cargo clippy --all-targets --all-features --locked -- -D warnings

需注意的重要 lint:

  • redundant_clone - 不必要的複製
  • large_enum_variant - 過大的變體(考慮使用 Box)
  • needless_collect - 過早的集合轉換

使用 #[expect(clippy::lint)] 而非 #[allow(...)],並附上理由註解。

測試

  • 測試命名要具描述性:process_should_return_error_when_input_empty()
  • 盡可能每個測試只有一個斷言
  • 公開 API 範例使用 doc 測試(///
  • 考慮使用 cargo insta 對產生的輸出進行快照測試

泛型與分派

  • 效能關鍵的程式碼優先使用泛型(靜態分派)
  • 僅在需要異質集合時使用 dyn Trait
  • 在 API 邊界使用 Box,而非內部

型別狀態模式

將有效狀態編碼在型別系統中,以便在編譯時期捕捉無效操作:

struct Connection<State> { /* ... */ _state: PhantomData<State> }
struct Disconnected;
struct Connected;

impl Connection<Connected> {
    fn send(&self, data: &[u8]) { /* 只有已連線才能傳送 */ }
}

文件

  • // 註解說明 為什麼(安全性、變通方法、設計理由)
  • /// doc 註解說明公開 API 的 什麼如何
  • 每個 TODO 都需要連結到一個 issue:// TODO(#42): ...
  • 函式庫啟用 #![deny(missing_docs)]