Prompt
関数の引数と返値がめっちゃ多い時どうする?
あはは、あるあるだね!関数の引数が10個も20個も並んで、戻り値も (i32, String, bool, Vec<u8>, ...) みたいな巨大なタプルになってくると、もはや「呪文」を唱えている気分になるよね。
情報工学的に言うと、これは**「関数の凝集度(Cohesion)」**が低くなっているサインであり、リファクタリングの絶好のチャンスだぜ!Rustでエレガントに解決する3つの戦略を教えるよ。🚀
1. 📦 「積の型」でカプセル化(構造体にする)
一番の王道は、関連する引数を一つの struct(構造体) にまとめることだ。
❌ ビフォー:引数地獄
Rust
fn create_user(name: &str, age: u32, email: &str, city: &str, zip: &str, is_admin: bool) { ... }
✅ アフター:構造体でスッキリ
Rust
struct UserProfile {
name: String,
age: u32,
email: String,
}
struct Address {
city: String,
zip: String,
}
// 役割ごとに分けると、何を受け取る関数か一目でわかる!
fn create_user(profile: UserProfile, address: Address, is_admin: bool) { ... }
こうすると、引数の順番を間違えるミス(city と email を逆にしちゃうとか)が型レベルで防げるようになるんだ。
2. 🛠️ 「Builder パターン」で段階的に組み立てる
引数が多い上に、**「一部はデフォルト値でいいんだけどな」**という時があるよね。RustにはJavaのような「関数のオーバーロード」がないから、Builder パターンがめちゃくちゃ輝くんだ!
Rust
let server = ServerBuilder::new()
.host("127.0.0.1")
.port(8080)
.timeout(30) // 設定したいものだけ呼ぶ
.build(); // 最後にガッチャンコ!
これなら引数の数が多くても、呼び出し側は迷わないし、読みやすい。
3. 🍱 戻り値は「意味のある名前」を付ける
戻り値が多すぎる場合は、巨大なタプルを返すのをやめて、専用の Output 構造体 を返そう。
❌ タプルだと「何番目が何だっけ?」となる
Rust
let (status, data, time, size) = process_request();
✅ 構造体なら名前でアクセスできる
Rust
struct ProcessResult {
status: u32,
payload: Vec<u8>,
elapsed_ms: u64,
}
let result = process_request();
println!("かかった時間: {}ms", result.elapsed_ms);
💡 見落とされがちな視点:その関数、やりすぎじゃない?
引数や戻り値が「めっちゃ多い」ということは、その関数が**「一つのことだけをやる(単一責任の原則)」**に反して、あれもこれも詰め込みすぎている可能性があるんだ。
-
入力の分割: 構造体にまとめる前に、「この引数を使う前半部分」と「あの引数を使う後半部分」で、関数自体を2つに分けられないか考えてみよう。
-
状態の保持: もし同じ引数を何度も色んな関数に回しているなら、それらをフィールドに持つ
structを作って、関数をimplメソッドにしてしまうのが Rust らしい設計だぜ!
🏁 まとめ
-
引数 構造体にまとめる。
-
オプション設定 Builder パターンを使う。
-
戻り値 タプルを卒業して、専用の構造体を返す。
「関数のシグネチャ(定義)」を綺麗に保つことは、未来の自分への最大のプレゼントだね。
次は、この Builder パターンを簡単に実装できる derive_builder みたいな外部クレートを使ってみる?それとも、もっと哲学的に「良い関数の切り出し方」について語り合う?😊✨
Would you like me to show you how to implement a basic Builder pattern from scratch in Rust?