Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

生成AI活用ガイドライン

Rust学習において生成AIを効果的に活用する方法をまとめました。

基本方針

┌─────────────────────────────────────────────────────┐
│                  理解すべき領域                      │
│  (AIに頼る前に自分で理解する)                       │
│                                                     │
│  ・所有権、借用、ライフタイム                         │
│  ・エラーメッセージの読み方                           │
│  ・基本的な型システム                                │
│  ・プロジェクト構造                                  │
│                                                     │
├─────────────────────────────────────────────────────┤
│                  AI活用推奨領域                       │
│  (積極的にAIを活用する)                            │
│                                                     │
│  ・ボイラープレートコード生成                         │
│  ・ライブラリの使い方                                │
│  ・テストコード生成                                  │
│  ・デバッグの補助                                    │
│                                                     │
└─────────────────────────────────────────────────────┘

人間が必ず理解すべきこと

1. 所有権とメモリ管理

なぜ人間が理解すべきか:

  • Rustの核心概念であり、すべてのコードに影響する
  • AIの生成コードでも所有権エラーは頻発する
  • 理解なしにAIの提案を採用すると、不適切な回避策を使いがち

学習のポイント:

#![allow(unused)]
fn main() {
// この3パターンを完全に理解する
let s1 = String::from("hello");
let s2 = s1;         // ムーブ
let s3 = s2.clone(); // クローン
let r = &s3;         // 借用
}

2. エラーメッセージの読解

なぜ人間が理解すべきか:

  • エラーの原因を理解しないと、同じ間違いを繰り返す
  • AIにエラーを丸投げすると、表面的な修正になりがち
  • Rustコンパイラのエラーは非常に親切で情報量が多い

実践:

# 必ず自分でエラーを読む習慣をつける
cargo build 2>&1 | less

# エラーコードの詳細を調べる
rustc --explain E0382

3. Result/Optionの扱い

なぜ人間が理解すべきか:

  • ほぼすべてのRustコードで使われる
  • エラー処理の設計に直接影響
  • unwrap()の乱用を防ぐ

理解すべきパターン:

#![allow(unused)]
fn main() {
// これらの違いを理解する
result.unwrap()      // パニックの可能性
result?              // エラー伝播
result.unwrap_or(default)  // デフォルト値
match result { ... }  // 明示的なハンドリング
}

4. プロジェクト構造

なぜ人間が理解すべきか:

  • ファイルの配置がモジュールシステムに直結
  • AIは既存の構造を無視した提案をすることがある
  • 保守性に大きく影響

理解すべき構造:

src/
├── main.rs      # mod宣言
├── lib.rs       # ライブラリのルート
├── module.rs    # mod module;
└── module/
    └── mod.rs   # mod module;(ディレクトリ版)

AI活用が効果的な領域

1. ボイラープレートコード

適している理由:

  • 定型的なコードは正確に生成できる
  • 時間の節約になる
  • ミスを減らせる

プロンプト例:

以下の構造体に対して、serde を使った
JSON シリアライゼーションのボイラープレートを生成してください。

struct User {
    id: u32,
    name: String,
    email: String,
}

期待される出力:

#![allow(unused)]
fn main() {
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}
}

2. ライブラリの使い方

適している理由:

  • ドキュメントを読む時間を短縮
  • 具体的な使用例を素早く得られる
  • 最新のAPIを把握

プロンプト例:

reqwest を使って JSON を POST する方法を教えてください。
エラーハンドリングも含めてください。

3. テストコード生成

適している理由:

  • テストケースの網羅性を高められる
  • 定型的なテストは正確に生成できる
  • テスト駆動開発を加速

プロンプト例:

以下の関数のユニットテストを生成してください。
正常系、異常系、エッジケースを含めてください。

fn divide(a: i32, b: i32) -> Option<i32> {
    if b == 0 { None } else { Some(a / b) }
}

4. エラー解決の補助

適している理由:

  • エラーメッセージの解釈を補助
  • 複数の解決策を提示してもらえる
  • 自分で考えた上での確認に使える

プロンプト例:

以下のエラーが出ています。
原因と解決方法を教えてください。

error[E0502]: cannot borrow `v` as mutable because
it is also borrowed as immutable

AIを使う際の注意点

1. 生成コードを必ず理解する

#![allow(unused)]
fn main() {
// AIが生成したコード
async fn fetch_data() -> Result<String, Box<dyn Error>> {
    // このコードの各部分を理解できるか?
    let response = reqwest::get("https://...")
        .await?           // <- なぜ?が必要?
        .text()
        .await?;          // <- なぜawaitが2回?
    Ok(response)
}
}

チェックリスト:

  • なぜこの型が使われているか理解した
  • エラー処理の方法を理解した
  • 所有権の流れを理解した

2. セキュリティに注意

避けるべきこと:

#![allow(unused)]
fn main() {
// AIが生成しがちな危険なパターン

// パスワードを環境変数からそのまま使用
let password = std::env::var("PASSWORD").unwrap();

// 入力値を検証せずにSQL文を構築
let query = format!("SELECT * FROM users WHERE id = {}", user_input);

// unwrap()の乱用
let data = file.read_to_string().unwrap();
}

正しいアプローチ:

#![allow(unused)]
fn main() {
// 環境変数は適切に処理
let password = std::env::var("PASSWORD")
    .expect("PASSWORD environment variable must be set");

// パラメータバインディングを使用
sqlx::query("SELECT * FROM users WHERE id = ?")
    .bind(user_input)

// 適切なエラーハンドリング
let data = file.read_to_string()
    .map_err(|e| AppError::FileRead(e))?;
}

3. 最新情報かどうか確認

AIの知識には期限があります:

#![allow(unused)]
fn main() {
// 古い書き方かもしれない
extern crate serde;  // Rust 2018以降は不要

// 非推奨のAPIかもしれない
std::mem::uninitialized()  // 非推奨

// バージョンが古いかもしれない
axum = "0.5"  // 最新は0.7
}

確認方法:

  • crates.io で最新バージョンを確認
  • 公式ドキュメントと照合
  • cargo clippy で警告をチェック

4. 文脈を伝える

悪いプロンプト:

Rustでログイン機能を作って

良いプロンプト:

Axum 0.7 と SQLx を使った Web API で、
セッションベースのログイン機能を実装したいです。

要件:
- POST /login でメールアドレスとパスワードを受け取る
- パスワードはargon2でハッシュ化されている
- ログイン成功時はセッションにユーザーIDを保存
- 適切なエラーレスポンスを返す

現在のプロジェクト構造:
src/
├── main.rs
├── handlers/
└── models/

使用しているクレート:
- axum = "0.7"
- sqlx = { version = "0.7", features = ["sqlite"] }
- tower-sessions = "0.12"

効果的なプロンプトのテンプレート

コード生成

[言語/フレームワーク]: Rust / Axum 0.7
[目的]: [何を達成したいか]
[制約]: [使用するクレート、バージョン、規約など]
[現在のコード]: [関連するコードがあれば]

期待する出力:
- [出力形式の指定]
- [エラーハンドリングの要件]
- [その他の要件]

デバッグ

[エラーメッセージ]:

[エラーの全文を貼り付け]


[関連するコード]:
```rust
[問題のコード]

### コードレビュー

以下のコードをレビューしてください。

観点:

  • 所有権とライフタイムの適切さ
  • エラーハンドリング
  • パフォーマンス
  • Rustらしい書き方か
#![allow(unused)]
fn main() {
[レビュー対象のコード]
}

## 学習段階別のAI活用

### Phase 0-1(入門期)

**推奨度: 低め**

- 基本文法は自分で書く
- エラーは自分で解決を試みる
- AIは「答え合わせ」に使う

### Phase 2(所有権学習期)

**推奨度: 低め**

- 所有権エラーは自分で理解する
- AIの提案より自分の理解を優先
- エラーメッセージの読み方を習得

### Phase 3-4(実践期)

**推奨度: 中程度**

- ボイラープレートはAIに任せる
- ライブラリの使い方はAIに聞く
- 生成コードは必ずレビュー

### Phase 5以降(応用期)

**推奨度: 高め**

- 設計相談にAIを活用
- コードレビューを依頼
- テスト生成を活用

## まとめ

### 人間が理解必須

| 項目 | 理由 |
|------|------|
| 所有権・借用 | Rustの根幹、すべてに影響 |
| エラーメッセージ | 自立したデバッグ能力 |
| Result/Option | エラー処理の基本 |
| プロジェクト構造 | 保守性・拡張性 |

### AI活用推奨

| 項目 | 効果 |
|------|------|
| ボイラープレート | 時間節約 |
| ライブラリ使用例 | 学習効率向上 |
| テスト生成 | 品質向上 |
| デバッグ補助 | 問題解決加速 |

### 鉄則

1. **生成コードは必ず理解してから使う**
2. **セキュリティに関わる部分は特に注意**
3. **文脈を詳しく伝える**
4. **最新情報かどうか確認する**
5. **AIは道具、理解は人間の仕事**