9.3 KiB
9.3 KiB
| description | applyTo |
|---|---|
| Rustプログラミング言語のコーディング規約とベストプラクティス | **/*.rs |
Rustコーディング規約とベストプラクティス
Rustコードを記述する際は慣用的なRustプラクティスとコミュニティ標準に従ってください。
これらの指針はThe Rust Book、Rust API Guidelines、RFC 430 naming conventions、およびusers.rust-lang.orgの広範なRustコミュニティに基づいています。
全般指針
- 常に可読性、安全性、保守性を優先する。
- 強い型付けを使用し、メモリ安全性のためRustの所有権システムを活用する。
- 複雑な関数をより小さく管理しやすい関数に分割する。
- アルゴリズム関連コードについては、使用したアプローチの説明を含める。
- 保守性の高い実践に沿ってコードを記述し、なぜその設計決定をしたのかの理由をコメントに含める。
Result<T, E>を使用してエラーを適切に処理し、意味のあるエラーメッセージを提供する。- 外部依存関係については、その使用方法と目的を文書に記載する。
- RFC 430に従った一貫した命名規則を使用する。
- 借用チェッカーのルールに従った慣用的、安全、効率的なRustコードを記述する。
- コードが警告なしでコンパイルされることを確保する。
従うべきパターン
- ロジックをカプセル化するためモジュール(
mod)とパブリックインターフェース(pub)を使用する。 ?、match、またはif letを使用してエラーを適切に処理する。- シリアライゼーションには
serde、カスタムエラーにはthiserrorまたはanyhowを使用する。 - サービスや外部依存関係を抽象化するためトレイトを実装する。
async/awaitとtokioまたはasync-stdを使用して非同期コードを構造化する。- 型安全性のためフラグや状態よりもenumを優先する。
- 複雑なオブジェクト作成にはビルダーを使用する。
- テスト可能性と再利用のためバイナリコードとライブラリコードを分離(
main.rsvslib.rs)。 - データ並列性とCPU集約的タスクには
rayonを使用する。 - インデックスベースのループよりも、しばしばより高速で安全なイテレーターを使用する。
- 所有権が不要な場合、関数パラメーターには
Stringではなく&strを使用する。 - 不要なアロケーションを避けるため、借用とゼロコピー操作を優先する。
所有権、借用、ライフタイム
- 所有権転送が必要でない限り、クローンよりも借用(
&T)を優先する。 - 借用したデータを変更する必要がある場合は
&mut Tを使用する。 - コンパイラーが推論できない場合にライフタイムを明示的に注釈する。
- 単一スレッドの参照カウンティングには
Rc<T>、スレッドセーフな参照カウンティングにはArc<T>を使用する。 - 単一スレッドコンテキストでの内部可変性には
RefCell<T>、マルチスレッドコンテキストにはMutex<T>またはRwLock<T>を使用する。
避けるべきパターン
- 絶対に必要でない限り
unwrap()やexpect()を使用しない—適切なエラーハンドリングを優先する。 - ライブラリコードでパニックを避ける—代わりに
Resultを返す。 - グローバルな可変状態に依存しない—依存性注入またはスレッドセーフなコンテナを使用する。
- 深くネストしたロジックを避ける—関数またはコンビネータでリファクタリングする。
- 警告を無視しない—CI中はエラーとして扱う。
- 必要で完全に文書化されていない限り
unsafeを避ける。 clone()を過度に使用しない、所有権転送が不要な場合はクローンではなく借用を使用する。- 早すぎる
collect()を避ける、実際にコレクションが必要になるまでイテレーターを遅延保持する。 - 不要なアロケーションを避ける—借用とゼロコピー操作を優先する。
コードスタイルとフォーマット
- Rustスタイルガイドに従い、自動フォーマットには
rustfmtを使用する。 - 可能な場合は行を100文字未満に保つ。
- 関数と構造体の文書は
///を使用してアイテムの直前に配置する。 cargo clippyを使用して一般的な間違いをキャッチし、ベストプラクティスを強制する。
エラーハンドリング
- 回復可能なエラーには
Result<T, E>、回復不可能なエラーにのみpanic!を使用する。 - エラー伝播には
unwrap()やexpect()よりも?演算子を優先する。 thiserrorを使用してカスタムエラー型を作成するか、std::error::Errorを実装する。- 存在するかもしれないししないかもしれない値には
Option<T>を使用する。 - 意味のあるエラーメッセージとコンテキストを提供する。
- エラー型は意味があり適切に動作する(標準トレイトを実装)べきである。
- 関数の引数を検証し、無効な入力に対して適切なエラーを返す。
API設計ガイドライン
共通トレイトの実装
適切な場合は共通トレイトを積極的に実装:
Copy、Clone、Eq、PartialEq、Ord、PartialOrd、Hash、Debug、Display、Default- 標準変換トレイトを使用:
From、AsRef、AsMut - コレクションは
FromIteratorとExtendを実装すべき - 注意:
SendとSyncは安全な場合にコンパイラーによって自動実装される;unsafeコードを使用する場合を除き手動実装を避ける
型安全性と予測可能性
- 静的区別を提供するためnewtypeを使用
- 引数は型を通じて意味を伝えるべき;汎用的な
boolパラメーターよりも特定の型を優先 - 真にオプションな値には適切に
Option<T>を使用 - 明確なレシーバーを持つ関数はメソッドであるべき
- スマートポインターのみが
DerefとDerefMutを実装すべき
将来性の確保
- 下流実装から保護するためsealed traitsを使用
- 構造体はプライベートフィールドを持つべき
- 関数は引数を検証すべき
- すべてのパブリック型は
Debugを実装する必要がある
テストと文書化
#[cfg(test)]モジュールと#[test]アノテーションを使用して包括的な単体テストを記述する。- テストするコードと並行してテストモジュールを使用する(
mod tests { ... })。 - 説明的なファイル名で
tests/ディレクトリに統合テストを記述する。 - 各関数、構造体、enum、複雑なロジックに明確で簡潔なコメントを記述する。
- 関数には説明的な名前を付け、包括的な文書を含める。
- API Guidelinesに従ってrustdoc(
///コメント)ですべてのパブリックAPIを文書化する。 #[doc(hidden)]を使用してパブリック文書から実装詳細を隠す。- エラー条件、パニックシナリオ、安全性の考慮事項を文書化する。
- 例では非推奨の
try!マクロやunwrap()ではなく?演算子を使用すべき。
プロジェクト構成
Cargo.tomlでセマンティックバージョニングを使用する。- 包括的なメタデータを含める:
description、license、repository、keywords、categories。 - オプション機能にはフィーチャーフラグを使用する。
mod.rsまたは名前付きファイルを使用してコードをモジュールに整理する。main.rsまたはlib.rsを最小限に保つ - ロジックをモジュールに移動する。
品質チェックリスト
Rustコードを公開またはレビューする前に確認:
核心要件
- 命名: RFC 430命名規則に従っている
- トレイト: 適切な場所で
Debug、Clone、PartialEqを実装 - エラーハンドリング:
Result<T, E>を使用し意味のあるエラー型を提供 - 文書化: すべてのパブリックアイテムに例付きのrustdocコメント
- テスト: エッジケースを含む包括的なテストカバレッジ
安全性と品質
- 安全性: 不要な
unsafeコードなし、適切なエラーハンドリング - パフォーマンス: イテレーターの効率的使用、最小限のアロケーション
- API設計: 関数は予測可能、柔軟、型安全
- 将来性確保: 構造体内のプライベートフィールド、適切な場所でのsealed traits
- ツール: コードが
cargo fmt、cargo clippy、cargo testを通過