生成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は道具、理解は人間の仕事**