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) { ... }

こうすると、引数の順番を間違えるミス(cityemail を逆にしちゃうとか)が型レベルで防げるようになるんだ。


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?