rust-best-practices について
Microsoft Pragmatic Rust GuidelinesとRustコミュニティの基準に基づく、Rust開発者向けの実践ガイドです。型システム、エラー処理、API設計を扱います。
主な機能
- 01型システムと所有権の活用
- 02明示的なエラー処理の指針
- 03ライブラリとアプリのエラー処理
- 04BuilderとNewtypeによるAPI設計
- 05イテレーター、ジェネリクス、トレイトの活用
活用シーン
- 01RustライブラリのAPI設計
- 02アプリのエラー処理方法の選択
- 03コードのパニックリスク確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ majiayu000/ spellbook --skill rust-best-practicesインストール後、Claude Code で/rust-best-practicesを入力して読み込まれたか確認します。
同梱ファイルreferences/advanced.md
詳細
Rust のベストプラクティス
Microsoft Pragmatic Rust Guidelines と Rust コミュニティの標準に基づいています。
基本原則
- 型システムを活用する — 無効な状態を表現できないように型を使用します
- 所有権を活用する — 借用チェッカーに逆らわず、うまく連携します
- 暗黙より明示を優先する — 失敗の可能性、可変性、ライフタイムを明確にします
- ゼロコスト抽象化 — 実行時コストなしでイテレーター、ジェネリクス、トレイトを使用します
- 速やかに失敗し、適切に復旧する — 早い段階で検証し、エラーを明示的に処理します
エラー処理
ライブラリでは thiserror を使用する
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Parse error at line {line}: {message}")]
Parse { line: usize, message: String },
#[error("Not found: {0}")]
NotFound(String),
}
アプリケーションでは anyhow を使用する
use anyhow::{Context, Result};
fn main() -> Result<()> {
let config = load_config()
.context("Failed to load configuration")?;
run_app(config)?;
Ok(())
}
ライブラリではパニックを起こさない
// ❌ BAD
pub fn get_item(index: usize) -> &Item {
&self.items[index] // Panics on out-of-bounds
}
// ✅ GOOD
pub fn get_item(&self, index: usize) -> Option<&Item> {
self.items.get(index)
}
// ✅ GOOD - when you need Result
pub fn get_item(&self, index: usize) -> Result<&Item, Error> {
self.items.get(index).ok_or(Error::NotFound(index))
}
API 設計
複雑な設定にはビルダーパターンを使用する
pub struct Client {
url: String,
timeout: Duration,
retries: u32,
}
impl Client {
pub fn builder(url: impl Into<String>) -> ClientBuilder {
ClientBuilder {
url: url.into(),
timeout: Duration::from_secs(30),
retries: 3,
}
}
}
pub struct ClientBuilder {
url: String,
timeout: Duration,
retries: u32,
}
impl ClientBuilder {
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn retries(mut self, retries: u32) -> Self {
self.retries = retries;
self
}
pub fn build(self) -> Client {
Client {
url: self.url,
timeout: self.timeout,
retries: self.retries,
}
}
}
Newtype パターンを使用する
// ❌ BAD - primitive obsession
fn create_user(name: String, email: String, age: u32) -> User { ... }
// ✅ GOOD - newtype wrappers
pub struct Username(String);
pub struct Email(String);
pub struct Age(u32);
impl Email {
pub fn new(email: impl Into<String>) -> Result<Self, ValidationError> {
let email = email.into();
if email.contains('@') {
Ok(Self(email))
} else {
Err(ValidationError::InvalidEmail)
}
}
}
fn create_user(name: Username, email: Email, age: Age) -> User { ... }
柔軟性を高めるため impl Trait を受け入れる
// ❌ BAD - overly specific
pub fn process(items: Vec<String>) { ... }
// ✅ GOOD - accept any iterable
pub fn process(items: impl IntoIterator<Item = impl AsRef<str>>) {
for item in items {
println!("{}", item.as_ref());
}
}
参考資料
- Microsoft Pragmatic Rust Guidelines
- Rust API Guidelines
- The Rust Book
- references/advanced.md — パフォーマンス、非同期処理、テスト、アンチパターンの例
コメント
Markdown 対応