135 lines
9.3 KiB
Markdown
135 lines
9.3 KiB
Markdown
---
|
||
description: 'Rustプログラミング言語のコーディング規約とベストプラクティス'
|
||
applyTo: '**/*.rs'
|
||
---
|
||
|
||
# Rustコーディング規約とベストプラクティス
|
||
|
||
Rustコードを記述する際は慣用的なRustプラクティスとコミュニティ標準に従ってください。
|
||
|
||
これらの指針は[The Rust Book](https://doc.rust-lang.org/book/)、[Rust API Guidelines](https://rust-lang.github.io/api-guidelines/)、[RFC 430 naming conventions](https://github.com/rust-lang/rfcs/blob/master/text/0430-finalizing-naming-conventions.md)、および[users.rust-lang.org](https://users.rust-lang.org)の広範なRustコミュニティに基づいています。
|
||
|
||
## 全般指針
|
||
|
||
- 常に可読性、安全性、保守性を優先する。
|
||
- 強い型付けを使用し、メモリ安全性のためRustの所有権システムを活用する。
|
||
- 複雑な関数をより小さく管理しやすい関数に分割する。
|
||
- アルゴリズム関連コードについては、使用したアプローチの説明を含める。
|
||
- 保守性の高い実践に沿ってコードを記述し、なぜその設計決定をしたのかの理由をコメントに含める。
|
||
- `Result<T, E>`を使用してエラーを適切に処理し、意味のあるエラーメッセージを提供する。
|
||
- 外部依存関係については、その使用方法と目的を文書に記載する。
|
||
- [RFC 430](https://github.com/rust-lang/rfcs/blob/master/text/0430-finalizing-naming-conventions.md)に従った一貫した命名規則を使用する。
|
||
- 借用チェッカーのルールに従った慣用的、安全、効率的なRustコードを記述する。
|
||
- コードが警告なしでコンパイルされることを確保する。
|
||
|
||
## 従うべきパターン
|
||
|
||
- ロジックをカプセル化するためモジュール(`mod`)とパブリックインターフェース(`pub`)を使用する。
|
||
- `?`、`match`、または`if let`を使用してエラーを適切に処理する。
|
||
- シリアライゼーションには`serde`、カスタムエラーには`thiserror`または`anyhow`を使用する。
|
||
- サービスや外部依存関係を抽象化するためトレイトを実装する。
|
||
- `async/await`と`tokio`または`async-std`を使用して非同期コードを構造化する。
|
||
- 型安全性のためフラグや状態よりもenumを優先する。
|
||
- 複雑なオブジェクト作成にはビルダーを使用する。
|
||
- テスト可能性と再利用のためバイナリコードとライブラリコードを分離(`main.rs` vs `lib.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](https://rust-lang.github.io/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`を通過 |