rust-skills について
Rust コードの作成、レビュー、リファクタリングに使う実践ガイドです。優先度別のルールで、所有権、エラー処理、非同期処理、並行処理、パフォーマンスなどを扱います。
主な機能
- 01優先度別に Rust の指針を整理
- 02所有権と借用を解説
- 03エラー処理と非同期コードを案内
- 04並行処理と unsafe コードを扱う
- 05API 設計と性能の指針を提示
- 06テスト、文書化、プロジェクト構成を網羅
活用シーン
- 01Rust の関数やモジュールを新規作成
- 02所有権や借用の問題をレビュー
- 03非同期・並行・unsafe 実装を改善
- 04Rust プロジェクトをリファクタリング・最適化
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ leonardomso/ rust-skills --skill rust-skillsインストール後、Claude Code で/rust-skillsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
AGENTS.mdCLAUDE.mdCHANGELOG.mdLICENSECONTRIBUTING.mdREADME.md.github/workflows/ci.ymlchecks/.gitignoreCargo.lockCargo.tomlREADME.mdcheck.shbaseline.txtgen.pyanalyze.pyrust-toolchain.tomlgen_index.pyvalidate.pychecks/src/lib.rsrules/anti-collect-intermediate.mdanti-clone-excessive.mdanti-index-over-iter.mdanti-expect-lazy.mdanti-format-hot-path.mdanti-empty-catch.mdanti-lock-across-await.mdanti-panic-expected.mdanti-over-abstraction.mdanti-premature-optimize.mdanti-stringly-typed.md詳細
Rust のベストプラクティス
高品質で慣用的、かつ高度に最適化された Rust コードを書くための包括的なガイドです。LLM によるコード生成とリファクタリングを支援するため、影響度に基づいて優先順位付けされた 26 カテゴリー、265 個のルールが含まれています。Rust 1.96(2024 エディション)に対応しています。
適用する場面
以下の場合に、これらのガイドラインを参照してください。
- Rust の関数、構造体、モジュールを新しく作成するとき
- エラー処理や非同期コードを実装するとき
- 並行処理、並列処理、または
unsafeコードを書くとき - ライブラリの公開 API を設計するとき
- 所有権や借用に関する問題についてコードをレビューするとき
- メモリ使用量を最適化したり、割り当てを減らしたりするとき
- ホットパスのパフォーマンスを調整するとき
- 既存の Rust コードをリファクタリングするとき
優先度別のルールカテゴリー
| 優先度 | カテゴリー | 影響度 | プレフィックス | ルール数 |
|---|---|---|---|---|
| 1 | 所有権と借用 | CRITICAL | own- | 12 |
| 2 | エラー処理 | CRITICAL | err- | 12 |
| 3 | メモリ最適化 | CRITICAL | mem- | 17 |
| 4 | unsafe コード | CRITICAL | unsafe- | 7 |
| 5 | API 設計 | HIGH | api- | 17 |
| 6 | Async/Await | HIGH | async- | 18 |
| 7 | 並行処理 | HIGH | conc- | 4 |
| 8 | コンパイラー最適化 | HIGH | opt- | 12 |
| 9 | 数値と算術の安全性 | HIGH | num- | 5 |
| 10 | 型安全性 | MEDIUM | type- | 13 |
| 11 | トレイトとジェネリクスの設計 | MEDIUM | trait- | 6 |
| 12 | 変換 | MEDIUM | conv- | 3 |
| 13 | const とコンパイル時処理 | MEDIUM | const- | 4 |
| 14 | Serde | MEDIUM | serde- | 8 |
| 15 | パターンマッチング | MEDIUM | pat- | 5 |
| 16 | マクロ | MEDIUM | macro- | 8 |
| 17 | クロージャ | MEDIUM | closure- | 5 |
| 18 | コレクション | MEDIUM | coll- | 4 |
| 19 | 命名規則 | MEDIUM | name- | 16 |
| 20 | テスト | MEDIUM | test- | 15 |
| 21 | ドキュメント | MEDIUM | doc- | 12 |
| 22 | 可観測性 | MEDIUM | obs- | 7 |
| 23 | パフォーマンスパターン | MEDIUM | perf- | 13 |
| 24 | プロジェクト構成 | LOW | proj- | 14 |
| 25 | Clippy と lint | LOW | lint- | 13 |
| 26 | アンチパターン | REFERENCE | anti- | 15 |
クイックリファレンス
1. 所有権と借用(CRITICAL)
own-borrow-over-clone-.clone()よりも&Tによる借用を優先するown-slice-over-vec-&Vec<T>ではなく&[T]を、&Stringではなく&strを受け取るown-cow-conditional- 条件付き所有権にはCow<'a, T>を使うown-arc-shared- スレッドセーフな共有所有権にはArc<T>を使うown-rc-single-thread- シングルスレッドのコンテキストで共有所有権を実現するにはRc<T>を使うown-refcell-interior- シングルスレッドコードで内部可変性を実現するにはRefCell<T>を使うown-mutex-interior- スレッド間で内部可変性を実現するにはMutex<T>を使うown-rwlock-readers- 書き込みより読み取りが大幅に多い場合はRwLock<T>を使うown-copy-small- 小さく単純な型にはCopyを実装するown-clone-explicit- コピーに意味のあるコストが伴う型には、明示的なCloneを使うown-move-large- 大きな型はコピーせずにムーブし、ムーブのコストが高い場合はBoxを使うown-lifetime-elision- ライフタイム省略規則に従い、必要な場合にのみ明示的なライフタイムを追加する
2. エラー処理(重大)
err-thiserror-lib- ライブラリのエラー型にはthiserrorを使用しますerr-anyhow-app- アプリケーションのエラー処理にはanyhowを使用しますerr-result-over-panic- 回復可能なエラーではパニックを起こさず、Result<T, E>を返しますerr-context-chain-.context()または.with_context()でコンテキストを追加しますerr-no-unwrap-prod- 本番コードではunwrap()を避け、?、expect()、またはエラー処理を使用しますerr-expect-bugs-only-expect()はユーザーエラーではなく、バグを示す不変条件に対してのみ使用しますerr-question-mark- 簡潔にエラーを伝播するには?演算子を使用しますerr-from-impl-?演算子を使えるよう、エラー変換用にFrom<E>を実装しますerr-source-chain-#[source]またはsource()メソッドでエラーチェーンを保持しますerr-lowercase-msg- エラーメッセージは小文字で始め、末尾に句読点を付けませんerr-doc-errors- ドキュメントコメントの# Errorsセクションでエラー条件を説明しますerr-custom-type- ドメイン固有の失敗に対してカスタムエラー型を定義します
3. メモリ最適化(重大)
mem-with-capacity- サイズが既知の場合はwith_capacity()を使用しますmem-smallvec- 通常は小さいコレクションにSmallVecを使用しますmem-arrayvec- ヒープ割り当てが発生しない固定容量のコレクションにはArrayVec<T, N>を使用しますmem-box-large-variant- 大きな列挙型バリアントを Box 化し、列挙型全体のサイズを削減しますmem-boxed-slice- 固定サイズのヒープデータにはVec<T>ではなくBox<[T]>を使用しますmem-thinvec- オーバーヘッドを最小限に抑えた nullable コレクションにはThinVec<T>を使用しますmem-clone-from- 繰り返しクローンする際に割り当てを再利用するにはclone_from()を使用しますmem-reuse-collections- ループ内で新しいコレクションを作成せず、コレクションをクリアして再利用しますmem-avoid-format- 文字列リテラルで済む場合はformat!()を避けますmem-write-over-format-format!()による割り当てではなく、既存のバッファにwrite!()を使用しますmem-arena-allocator- 一括割り当てにはアリーナアロケーターを使用しますmem-zero-copy- スライスとBytesを使ったゼロコピーのパターンを使用しますmem-compact-string- メモリに制約のある文字列ストレージにはコンパクトな文字列型を使用しますmem-smaller-integers- メモリ使用量を削減するため、適切なサイズの整数を使用しますmem-assert-type-size- 型サイズの意図しない増大を防ぐため、静的アサーションを使用しますmem-take-replace- クローンせずに&mutから値を取り出すにはmem::take/mem::replaceを使用しますmem-drop-order- ドロップ順序を把握して制御します。構造体のフィールドは上から下へ、ローカル変数は逆順にドロップされます
4. 安全でないコード(CRITICAL)
unsafe-safety-comment- すべてのunsafeブロックの上に// SAFETY:コメントを、すべてのunsafe fnに# Safetyセクションを記述します。unsafe-minimize-scope-unsafeブロックは可能な限り小さくします。安全でない操作だけを対象にし、その周囲の安全なコードは含めません。unsafe-miri-ci-unsafeコードを含むすべてのクレートについて、CI でcargo miri testを実行します。unsafe-maybeuninit- 初期化されていないメモリにはMaybeUninit<T>を使用します。有効性の不変条件がある型には、mem::uninitialized()やmem::zeroed()を決して使用しません。unsafe-extern-block- Rust 2024 では、externブロックをunsafe extern { }で囲み、各項目にsafeまたはunsafeを指定します。unsafe-send-sync-manual-SendまたはSyncを手動で実装する場合は、不変条件を文書化します。コンパイラーによる自動導出を優先します。unsafe-no-mangle-unsafe- Rust 2024 では、属性をそのまま使うのではなく、#[unsafe(no_mangle)]、#[unsafe(export_name = "...")]、#[unsafe(link_section = "...")]と記述します。
5. API 設計(HIGH)
api-builder-pattern- 複雑な構築には Builder パターンを使用しますapi-builder-must-use- ビルダーメソッドに#[must_use]を付け、結果が暗黙に破棄されるのを防ぎますapi-newtype-safety- 意味の異なる値が混同されないよう、newtype を使用しますapi-typestate- 型システムでステートマシンの不変条件を表現するには、typestate パターンを使用しますapi-sealed-trait- 外部からの実装を防ぎつつ使用を許可するには、sealed trait を使用しますapi-extension-trait- 外部の型にメソッドを追加するには、拡張トレイトを使用しますapi-parse-dont-validate- 境界で検証済みの型にパースしますapi-impl-into- 柔軟な API にするにはimpl Into<T>を受け入れ、変換にはFrom<T>を実装しますapi-impl-asref- 内部データを借用するだけでよい場合は、AsRef<T>を使用しますapi-must-use- 結果を無視するとバグになる可能性が高い型や関数には、#[must_use]を付けますapi-non-exhaustive- 前方互換性のため、公開される enum と struct に#[non_exhaustive]を使用しますapi-from-not-into-Into<U>ではなくFrom<T>を実装します。Fromを実装すればIntoも自動的に使えますapi-default-impl- 妥当なデフォルト値を持つ型にはDefaultを実装しますapi-common-traits- 公開型には標準トレイト(Debug、Clone、PartialEq など)を実装しますapi-serde-optional- ライブラリークレートでは、serde を必須の依存関係ではなく、機能フラグにしますapi-impl-fromiterator- コレクション型にはFromIteratorとExtendを、3 種類すべての参照形式にはIntoIteratorを実装しますapi-operator-overload- 演算子のオーバーロードは、意味が自然で、予想外にならない場合に限って行います
6. Async/Await(HIGH)
async-tokio-runtime- ワークロードに応じて Tokio ランタイムを適切に設定しますasync-no-lock-await-.awaitをまたいでMutex/RwLockを保持しないでくださいasync-spawn-blocking- CPU 負荷の高い処理にはspawn_blockingを使用しますasync-tokio-fs- 非同期コードではstd::fsの代わりにtokio::fsを使用しますasync-cancellation-token- グレースフルシャットダウンとタスクのキャンセルにはCancellationTokenを使用しますasync-join-parallel- 独立したフューチャーを並行実行するにはjoin!またはtry_join!を使用しますasync-try-join- エラー時に早期リターンする、失敗する可能性のある操作の並行実行にはtry_join!を使用しますasync-select-racing- フューチャーを競合させ、最初に完了したものを処理するにはselect!を使用しますasync-bounded-channel- バックプレッシャーを適用し、メモリの無制限な増加を防ぐには、バウンド付きチャネルを使用しますasync-mpsc-queue- タスク間の非同期メッセージキューにはmpscチャネルを使用しますasync-broadcast-pubsub- すべてのサブスクライバーがすべてのメッセージを受信する pub/sub には、broadcastチャネルを使用しますasync-watch-latest- 複数の監視者と最新の値を共有するには、watchチャネルを使用しますasync-oneshot-response- リクエスト/レスポンスのパターンにはoneshotチャネルを使用しますasync-joinset-structured- 動的なスポーン済みタスクの集合を管理するにはJoinSetを使用しますasync-clone-before-await- サスペンド中に参照を保持しないよう、await ポイントの前に Arc/Rc データをクローンしますasync-fn-in-trait-async_traitマクロの代わりに、トレイトでネイティブのasync fn(安定版 1.75)を使用しますasync-async-fn-bounds-F: Fn() -> Fut, Fut: Futureの代わりに、AsyncFn/AsyncFnMut/AsyncFnOnce境界を使用しますasync-cancel-safety-tokio::select!の分岐で使用するフューチャーがキャンセルセーフであることを確認します
7. Concurrency(HIGH)
conc-rayon-par-iter- CPU バウンドのデータ並列処理には rayon のpar_iter()を使用しますconc-scoped-threads- スレッド間でスタックデータを借用するにはstd::thread::scopeを使用しますconc-atomic-ordering- 各アトミック操作には、正しく動作する範囲で最も弱いメモリOrderingを使用しますconc-thread-local-static mutよりもCell/RefCellを使ったthread_local!を優先します
8. コンパイラー最適化(HIGH)
opt-inline-small- 小さなホット関数には#[inline]を使用しますopt-inline-always-rare-#[inline(always)]は控えめに使用し、プロファイリングで重要なホットパスと確認できた場合に限りますopt-inline-never-cold- エラーパスや実行頻度の低いコードには#[inline(never)]と#[cold]を使用しますopt-cold-unlikely- コンパイラーの最適化を助けるため、発生しにくいコードパスに#[cold]を付けますopt-likely-hint- 発生しやすい分岐を示すにはコード構造を利用し、nightly では組み込み関数を使用しますopt-lto-release- リリースビルドで LTO を有効にしますopt-codegen-units- リリースビルドで最大限の最適化を行うには、codegen-units = 1を設定しますopt-pgo-profile- 最大限のパフォーマンスを実現するには、プロファイル誘導最適化(PGO)を使用しますopt-target-cpu- デプロイ先が既知の場合に最大限のパフォーマンスを得るには、target-cpu=nativeを使用しますopt-bounds-check- ホットパスで境界チェックをなくせるイテレーターやパターンを使用しますopt-simd-portable- アーキテクチャを問わずベクトル化演算を行うには、ポータブル SIMD を使用しますopt-cache-friendly- キャッシュ効率の高いアクセスパターンになるよう、データを整理します
9. 数値と算術の安全性(HIGH)
num-overflow-explicit- 整数オーバーフローを明示的に処理します:checked_/saturating_/wrapping_/overflowing_num-cast-try-from- 縮小キャストにasを使用せず、拡大にはFrom、縮小にはTryFromを使用しますnum-float-compare- 浮動小数点数を==で比較せず、許容誤差を使用します。順序付けにはtotal_cmpを使用しますnum-saturating-clamp-clampと飽和算術で値を範囲内に収めますnum-nonzero- ゼロを禁止し、ニッチ最適化を利用するにはNonZero*型を使用します
10. 型の安全性(MEDIUM)
type-newtype-ids- ID を新しい型でラップします:UserId(u64)type-newtype-validated- 構築時に検証を強制するには、新しい型を使用しますtype-enum-states- 相互に排他的な状態には列挙型を使用しますtype-option-nullable- 値が存在しない可能性がある場合はOption<T>を使用しますtype-result-fallible- 失敗する可能性のある操作にはResult<T, E>を使用しますtype-phantom-marker- 実行時コストなしに型の関係を表すにはPhantomDataを使用しますtype-never-diverge- 戻ることのない関数には!(never 型)を使用しますtype-generic-bounds- トレイト境界は必要な箇所にのみ追加し、読みやすさのために where 句を優先しますtype-no-stringly- 文字列型 API を避け、列挙型、新しい型、または検証済みの型を使用しますtype-repr-transparent- FFI コンテキストで新しい型を使用する場合は#[repr(transparent)]を使用しますtype-deref-coercion-Deref/DerefMutはスマートポインター型と透過的なラッパー型にのみ実装しますtype-display-vs-debug- ユーザー向け出力にはDisplay、診断にはDebugを使用し、決して入れ替えないでくださいtype-numeric-fmt- 数値の新しい型にはLowerHex、UpperHex、Octal、Binaryを実装します
11. トレイトとジェネリクスの設計(MEDIUM)
trait-associated-type-vs-generic- 各実装の出力型が必ず1つだけの場合は関連型を使用し、型が複数の入力型に対してトレイトを実装できる場合はジェネリックパラメーターを使用しますtrait-blanket-impl- 境界を満たすすべての型に動作を提供するには、ブランケット実装impl<T: Bound> Trait for Tを使用しますtrait-coherence-newtype- オーファンルールを守り、外部トレイトを外部型に実装するには、その型をニュータイプでラップしますtrait-default-methods- 必須メソッドを少数定義し、それらを基にしたデフォルト実装のメソッドを追加してトレイトを定義しますtrait-dyn-vs-generic- 静的ディスパッチ(ジェネリクス/impl Trait)と動的ディスパッチ(dyn Trait)を意図的に選択しますtrait-object-safety-dyn Traitが必要な場合は、トレイトを dyn 互換(オブジェクトセーフ)に保ちます
12. 変換(MEDIUM)
conv-tryfrom-fallible- 失敗する可能性がある変換には、個別の変換関数ではなくTryFromを実装しますconv-fromstr-parsing- 文字列から型への変換でstr::parseを使えるようにするには、FromStrを実装しますconv-asmut-mutable- 具体的な可変参照ではなくimpl AsMut<T>を受け入れ、可変の借用入力に柔軟に対応します
13. 定数とコンパイル時処理(MEDIUM)
const-block- コンパイル時の評価やアサーションには、インラインのconst { }ブロックを使用しますconst-fn- コンパイル時に実行できる関数はconst fnにしますconst-generics- const ジェネリクス<const N: usize>で値をパラメーター化しますconst-vs-static- インライン化される値にはconstを、アドレスが1つのインスタンスにはstaticを使用します
14. Serde(MEDIUM)
serde-rename-all-#[serde(rename_all = ...)]で外部の命名規則に合わせますserde-default-compat- 任意のフィールドや後方互換性が必要なフィールドには#[serde(default)]を使用しますserde-skip-empty-skip_serializing_ifで空のフィールドを省略しますserde-flatten-#[serde(flatten)]でネストされた構造体をインライン化するか、追加のキーを取り込みますserde-enum-representation- 列挙型のタグ付け方法(外部タグ、内部タグ、隣接タグ、タグなし)を意図的に選択しますserde-deny-unknown-fields-#[serde(deny_unknown_fields)]で予期しないキーを拒否しますserde-custom-with-with/serialize_with/deserialize_withでフィールドのシリアライズ/デシリアライズをカスタマイズしますserde-try-from-validate-#[serde(try_from = "Raw")]でデシリアライズ時に検証します
15. パターンマッチング(MEDIUM)
pat-let-else- パターンを取り出して早期リターンするにはlet ... elseを使用しますpat-matches-macro- ブール値を返すパターン判定にはmatches!()を使用しますpat-if-let-chains-if letチェーンでパターンの束縛と条件を組み合わせますpat-exhaustive-enum- 所有する列挙型を漏れなくマッチさせ、新しいバリアントを隠してしまう包括的な_は避けますpat-at-bindings-@束縛を使用し、値をパターンと照合しながらその値をキャプチャします
16. マクロ(MEDIUM)
macro-prefer-functions- 関数やジェネリックでは表現できない場合にのみ、マクロを使いますmacro-rules-hygiene-macro_rules!の衛生性を活用し、自クレートのアイテムへのパスには$crateを使いますmacro-fragment-specifiers- 可能な場合は、生の:ttではなく、正確なフラグメント指定子でキャプチャしますmacro-export-crate-path-#[macro_export]を使って宣言的マクロをエクスポートし、明確なインポートパスを用意しますmacro-private-helpers- マクロが生成するヘルパーアイテムを#[doc(hidden)] pub mod __privateの背後に隠しますmacro-proc-two-crate- 手続き型マクロを専用のproc-macro = trueクレートに配置し、ファサードから再エクスポートしますmacro-proc-syn-quote-syn、quote、proc-macro2を使って手続き型マクロを構築しますmacro-proc-error-spans- 手続き型マクロのエラーはスパン付きのコンパイルエラーとして報告し、決してパニックさせません
17. クロージャ(MEDIUM)
closure-fn-trait-bounds- コールバックに必要な最も制約の少ないFnトレイトを要求します(FnOnce⊇FnMut⊇Fn)closure-impl-fn-return- クロージャはBox<dyn Fn>ではなく、impl Fn/FnMut/FnOnceとして返しますclosure-move-capture- 現在のスコープより長く存続するクロージャにはmoveを使います。元の値を保持するには、moveの前にクローンしますclosure-static-vs-dyn- ホットなコールバックにはimpl Fn(ジェネリック)を受け取り、コードサイズを削減したり、格納したりする場合は&dyn Fn/Box<dyn Fn>を使いますclosure-disjoint-capture- 使用するものだけをキャプチャし、エディション 2021 のクロージャにおけるフィールド単位のキャプチャを活用します
18. コレクション(MEDIUM)
coll-binaryheap- 優先度付きキューや、最大値の繰り返し取り出しにはBinaryHeapを使いますcoll-map-choice- アクセスパターンに応じてマップを選びます。高速で順序なしのHashMap、ソート済み/範囲検索用のBTreeMap、挿入順を保持するIndexMapを使いますcoll-seq-choice- 通常はVecを使います。キュー/デックの動作にはVecDequeを使い、LinkedListは避けますcoll-set-membership- 要素の有無の判定や重複排除にはVec::containsによる線形検索ではなく、HashSet/BTreeSetを使います
19. 命名規則(MEDIUM)
name-types-camel- 型、トレイト、列挙型の名前にはUpperCamelCaseを使用しますname-variants-camel- 列挙型のバリアントにはUpperCamelCaseを使用しますname-funcs-snake- 関数、メソッド、変数、モジュールにはsnake_caseを使用しますname-consts-screaming- 定数と静的変数にはSCREAMING_SNAKE_CASEを使用しますname-lifetime-short- 短く慣例的なライフタイム名を使用します:'a、'b、'de、'srcname-type-param-single- 型パラメーターには大文字1文字を使用します:T、E、K、Vname-as-free-as_接頭辞:所有権を伴わない参照変換name-to-expensive- 割り当てや計算を伴うコストの高い変換にはto_接頭辞を使用しますname-into-ownership- 所有権を消費する変換にはinto_接頭辞を使用しますname-no-get-prefix- 単純なゲッターではget_接頭辞を省略しますname-is-has-bool- ブール値を返すメソッドにはis_、has_、can_、should_接頭辞を使用しますname-iter-convention- イテレータメソッドにはiter/iter_mut/into_iterを使用しますname-iter-method- イテレータメソッドには一貫してiter()、iter_mut()、into_iter()という名前を付けますname-iter-type-match- イテレータ型には、元となるメソッドに基づいた名前を付けますname-acronym-word- 識別子では頭字語を単語として扱います:HTTPServerではなくHttpServername-crate-no-rs- クレート名に-rsや-rustを付けないでください
20. テスト(MEDIUM)
test-cfg-test-module- 各モジュール内の#[cfg(test)] mod tests { }にユニットテストを配置しますtest-use-super- テストモジュールではuse super::*;を使用して親モジュールの項目にアクセスしますtest-integration-dir- 統合テストはtests/ディレクトリに配置しますtest-descriptive-names- テスト内容が分かる、説明的な名前を付けますtest-arrange-act-assert- Arrange、Act、Assertの各セクションを明確にしてテストを構成しますtest-proptest-properties- プロパティベーステストにはproptestを使用しますtest-mockall-mocking- トレイトのモックにはmockallを使用しますtest-mock-traits- テストでモックを利用できるよう、依存関係にはトレイトを使用しますtest-fixture-raii- テストを自動的にクリーンアップするにはRAIIパターン(Dropトレイト)を使用しますtest-tokio-async- 非同期テストには#[tokio::test]を使用しますtest-should-panic- コードが想定どおりにパニックすることをテストするには#[should_panic]を使用しますtest-criterion-bench- ベンチマークにはcriterionを使用しますtest-doctest-examples- ドキュメントの例は、実行可能なドキュメントテストとして維持しますtest-loom-concurrency- ロックフリーコードや並行コードを網羅的にテストするにはloomを使用しますtest-snapshot-testing- 複雑な出力やシリアライズされた出力にはスナップショットテスト(insta)を使用します
21. ドキュメント(MEDIUM)
doc-all-public- すべての公開項目に///のドキュメントコメントを記述しますdoc-module-inner- モジュールレベルのドキュメントには//!を使用しますdoc-examples-section- 実行可能なコードを含む# Examplesを記述しますdoc-errors-section- 失敗する可能性がある関数には# Errorsセクションを記述しますdoc-panics-section- パニックを起こす可能性がある関数には# Panicsセクションを記述しますdoc-safety-section- unsafe 関数には# Safetyセクションを記述しますdoc-question-mark- 例では.unwrap()ではなく?を使用しますdoc-hidden-setup- 例のセットアップコードを非表示にするには#接頭辞を使用しますdoc-intra-links- 型や項目への参照にはドキュメント内リンクを使用しますdoc-link-types- 関連する型や関数をつなぐにはドキュメント内リンクを使用しますdoc-cargo-metadata- 公開するクレートのCargo.tomlメタデータを設定しますdoc-crate-readme-#![doc = include_str!("../README.md")]を使用して、README とクレートルートのドキュメントを統一します
22. 可観測性(MEDIUM)
obs-tracing-over-log-println!や単純なlogの代わりに、構造化され、スパンを認識する診断情報にはtracingを使用しますobs-library-facade- ライブラリは tracing/log ファサードを介して出力し、サブスクライバーをインストールしませんobs-structured-fields- メッセージ文字列に値を埋め込むのではなく、構造化されたキーと値のフィールドを記録しますobs-instrument-spans-#[tracing::instrument]とスパンを使用して、非同期タスクやリクエストにコンテキストを付与しますobs-levels-filter- ログレベルを適切に使用し、EnvFilter/RUST_LOGでフィルタリングしますobs-error-chain- エラーは原因のチェーン全体とともにログに記録し、各エラーを一度だけ記録しますobs-no-sensitive-data- シークレットや PII は決してログに記録せず、マスキングするか省略します
23. パフォーマンスパターン(MEDIUM)
perf-iter-over-index- 手動のインデックス操作よりイテレーターを優先しますperf-iter-lazy- イテレーターは遅延評価のままにし、必要な場合にのみ収集しますperf-collect-once- 中間イテレーターを収集しないでくださいperf-entry-api- マップの挿入または更新には entry API を使用しますperf-drain-reuse- drain を使用して割り当てを再利用しますperf-extend-batch- 一括挿入には extend を使用しますperf-chain-avoid- ホットループでは chain を避けますperf-collect-into- コンテナーを再利用するには collect_into を使用しますperf-black-box-bench- ベンチマークでは black_box を使用しますperf-release-profile- リリースプロファイルの設定を最適化しますperf-profile-first- 最適化の前にプロファイリングを行いますperf-ahash- DoS 耐性が不要な場合は、より高速なハッシャー(ahash/FxHashMap)を使用しますperf-io-buffering- 小さな操作を多数行う場合は、Read/WriteをBufReader/BufWriterでラップします
24. プロジェクト構成(低)
proj-lib-main-split-main.rsを最小限に保ち、ロジックはlib.rsに置きますproj-mod-by-feature- 型ではなく機能ごとにモジュールを整理しますproj-flat-small- 小規模なプロジェクトはフラットな構成にしますproj-mod-rs-dir- 複数ファイルからなるモジュールには mod.rs を使用しますproj-pub-crate-internal- 内部 API には pub(crate) を使用しますproj-pub-super-parent- 親モジュールからのみ参照可能にするには pub(super) を使用しますproj-pub-use-reexport- 明確な公開 API を提供するには pub use を使用しますproj-prelude-module- 共通のインポート用に prelude モジュールを作成しますproj-bin-dir- 複数のバイナリは src/bin/ に配置しますproj-workspace-large- 大規模なプロジェクトではワークスペースを使用しますproj-workspace-deps- クレート間でバージョンを統一するには、ワークスペースの依存関係の継承を使用しますproj-feature-additive- Cargo の機能は厳密に追加的になるよう設計しますproj-msrv-declare- Cargo.toml でrust-version(MSRV)を宣言し、CI でテストしますproj-build-rs-minimal-build.rsは最小限かつ決定的で、冪等性を保ちます
25. Clippy とリンティング(低)
lint-deny-correctness-#![deny(clippy::correctness)]lint-warn-suspicious- バグの可能性が高いコードを検出するため、clippy::suspicious を有効にしますlint-warn-style- 慣用的なコードにするため、clippy::style を有効にしますlint-warn-complexity- コードを簡潔にするため、clippy::complexity を有効にしますlint-warn-perf- パフォーマンスを改善するため、clippy::perf を有効にしますlint-pedantic-selective- clippy::pedantic を選択的に有効にしますlint-missing-docs- 公開項目のドキュメントが不足している場合に警告しますlint-unsafe-doc- unsafe ブロックにドキュメントを必須にしますlint-cargo-metadata- 公開するクレートでは clippy::cargo を有効にしますlint-rustfmt-check- CI で cargo fmt --check を実行しますlint-workspace-lints- 一貫して適用するため、ワークスペースレベルでリンティングを設定しますlint-cfg-check- 機能ゲートの誤記を検出するため、unexpected_cfgsを有効にし、既知の cfg を宣言しますlint-clippy-nursery-selected-clippy::nurseryの価値の高いリンティングを選択的に有効にし、グループ全体は有効にしません
26. アンチパターン(参考)
anti-unwrap-abuse- 本番コードでは.unwrap()を使用しないでくださいanti-expect-lazy- 回復可能なエラーには expect を使用しないでくださいanti-clone-excessive- 借用で済む場合はクローンしないでくださいanti-lock-across-await- await ポイントをまたいでロックを保持しないでくださいanti-string-for-str- &str で済む場合は &String を受け取らないでくださいanti-vec-for-slice- &[T] で済む場合は &Vec を受け取らないでくださいanti-index-over-iter- イテレーターで済む場合はインデックスを使用しないでくださいanti-panic-expected- 想定内または回復可能なエラーでパニックを起こさないでくださいanti-empty-catch- エラーを黙って無視しないでくださいanti-over-abstraction- 過剰なジェネリクスで抽象化しすぎないでくださいanti-premature-optimize- プロファイリングの前に最適化しないでくださいanti-type-erasure- impl Trait で済む場合は Box を使用しないでくださいanti-format-hot-path- ホットパスで format! を使用しないでくださいanti-collect-intermediate- 中間イテレーターを collect しないでくださいanti-stringly-typed- enum やニュータイプで型安全性を確保できる場合は文字列を使用しないでください
推奨される Cargo.toml 設定
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true
[profile.bench]
inherits = "release"
debug = true
strip = false
[profile.dev]
opt-level = 0
debug = true
[profile.dev.package."*"]
opt-level = 3 # Optimize dependencies in dev
使用方法
このスキルでは、すぐに参照できるルール識別子を提供します。Rust コードを生成またはレビューする際は、次の手順に従ってください。
- タスクの種類に応じて、関連するカテゴリを確認します
- 一致するプレフィックスのルールを適用します
- 優先順位を付けます(CRITICAL > HIGH > MEDIUM > LOW)
- 詳細な例については、
rules/内のルールファイルを確認します
タスク別のルール適用
| タスク | 主なカテゴリ |
|---|---|
| 新しい関数 | own-、err-、name-、pat- |
| 新しい構造体/API | api-、type-、conv-、doc- |
| 非同期コード | async-、own- |
| 並行処理/並列処理 | conc-、async-、own- |
| unsafe コード | unsafe-、type-、test- |
| エラー処理 | err-、api-、pat- |
| 型変換 | conv-、api- |
| シリアライズ(serde) | serde-、type-、api- |
| 数値/算術演算 | num-、type- |
| マクロ/コード生成 | macro-、anti- |
| クロージャー/コールバック | closure-、type- |
| ロギング/可観測性 | obs-、err- |
| メモリ最適化 | mem-、own-、perf- |
| パフォーマンス調整 | opt-、mem-、perf- |
| コードレビュー | anti-、lint- |
出典と帰属
このスキルは、Rust の公式ガイダンス、定評のある書籍、および広く使われているクレートのパターンを独自にまとめたものです。Rust プロジェクトやクレートの作者とは提携しておらず、推奨も受けていません。本文とコード例はオリジナルです。
Rust の公式ドキュメント
- The Rust Reference
- Rust API Guidelines
- The Rustonomicon(unsafe コード)
- Rust 2024 Edition Guide
- The Cargo Book
- 標準ライブラリのドキュメントおよびリリースノート
書籍とガイド
- The Rust Performance Book — Nicholas Nethercote
- Rust Design Patterns — rust-unofficial
- Rust Atomics and Locks — Mara Bos
- Effective Rust — David Drysdale
ツール
イディオムの参考として調査した実際のコードベース
- ripgrep、tokio、serde、clap、polars、axum、cargo、hyper、bevy、rayon、および dtolnay のクレート(thiserror、anyhow、syn)
このプロジェクトは MIT ライセンスです。参照先の上流資料は、それぞれ独自のライセンスで提供されています(Rust の公式ドキュメントと API Guidelines は MIT / Apache-2.0 のデュアルライセンスです)。
コメント
Markdown 対応