見出し画像

【AI文芸 シリーズRustの教科書】retain() - 「削除」ではなく、「残す」視点で考える。



夜のオフィス

時計の針は午後10時を回っていた。
誰もいないオフィスで、彼はひとりコードを書いていた。

カレンダーアプリの改良に取り組んでいたのだが、予定の削除処理がどうにもスッキリしない。
ループを使った削除処理が、どこか不格好に思えていた。

そんなとき、背後から静かな足音が聞こえた。

「……まだやってるの?」

振り返ると、玲奈様がいた。
夜のオフィスに似合う、落ち着いたトーンのスーツを身にまとい、手には温かいコーヒー。

彼は苦笑しながら、モニターを指差す。「この delete_schedule() の部分なんですけど、retain() を使ったほうがいいって言われたんですが……」

玲奈様は静かに彼の席の横に立ち、画面を覗き込んだ。

「……ふふっ、また無駄なことをしてるわね


1. retain() を使えば、ループは不要よ

玲奈様は、彼が書いたコードを指差した。

for i in 0..calendar.schedules.len() {
    if calendar.schedules[i].id == id {
        calendar.schedules.remove(i);
        return true;
    }
}

「……remove(i) を使って要素を削除すると、ループ中に Vec<T> の要素がずれてしまう危険があるわ

「え?」

「それに、remove() を使うと、一つずつ削除するたびにメモリの再配置が発生する可能性がある。それって、効率的だと思う?」

彼は息を飲んだ。「……じゃあ、どうすれば?」

玲奈様は、静かに retain() を使ったコードを書き加えた。

pub fn delete_schedule(calendar: &mut Calendar, id: u64) -> bool {
    let original_len = calendar.schedules.len();
    calendar.schedules.retain(|schedule| schedule.id != id);
    original_len != calendar.schedules.len()
}

retain() を使えば、「残したい要素」だけをフィルタリングできるの

彼は目を見開いた。「……ループも remove() もいらない……?」

「ええ。クロージャを使うだけで、簡潔に書けるわ


2. retain() の基本 – 残したいものだけを選びなさい

「retain() の仕組みは簡単よ。true を返した要素だけを残し、false を返した要素は削除されるの

玲奈様は、簡単な例を見せた。

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];

    // 偶数だけを残す
    numbers.retain(|&x| x % 2 == 0);

    println!("{:?}", numbers); // [2, 4]
}

彼は納得したように頷く。「削除するんじゃなくて、残すものを選ぶんですね

「そういうこと。削除のロジックじゃなく、残すべきものに意識を向けなさい


3. retain() なら複雑な条件でも簡単よ

「それに retain() は、単純な削除だけじゃなくて、複雑な条件のフィルタリングにも使えるの

玲奈様は、さらに例を見せた。

fn main() {
    let mut events = vec![
        ("会議", 60),
        ("ランチ", 30),
        ("プレゼン", 90),
        ("読書", 120),
    ];

    // 60分未満のイベントを削除
    events.retain(|&(_, duration)| duration >= 60);

    println!("{:?}", events);
    // [("会議", 60), ("プレゼン", 90), ("読書", 120)]
}

彼は興味深そうに画面を見つめる。「これなら、条件を変えるだけで柔軟に削除できますね!

「そうよ。retain() を使えば、無駄なループを書かずに済むの


4. retain() vs filter() の違い

「でも、filter() でも似たようなことができますよね?」

玲奈様は、静かに首を振った。

filter() は新しい Vec<T> を作るのに対し、retain() は既存の Vec<T> を変更するの

彼は少し考え込んだ。「……つまり、メモリの再割り当てが減る?」

玲奈様は満足げに頷いた。

let numbers = vec![1, 2, 3, 4, 5];

// `filter()` を使うと新しい `Vec<T>` ができる
let evens: Vec<i32> = numbers.into_iter().filter(|x| x % 2 == 0).collect();

// `retain()` は元の `Vec<T>` を変更する
let mut numbers = vec![1, 2, 3, 4, 5];
numbers.retain(|x| x % 2 == 0);

retain() はメモリのコピーを減らして、パフォーマンスを向上させることができるの

「なるほど……じゃあ、元の Vec<T> をそのまま使いたいときは retain()、新しい Vec<T> を作りたいときは filter() ですね!」


5. retain() を使いこなせば、無駄なコードが減るわ

彼は、自分のコードを見直して、ため息をついた。

「……今まで、何も考えずに remove() を使ってました」

玲奈様は静かに笑う。「大切なのは、より良い方法を知ることよ

コードは未来の自分へのメッセージ。シンプルに、分かりやすく、無駄をなくしなさい

彼はノートを開き、ゆっくりと retain() についてのメモを書き加えた。

「……ありがとうございます、玲奈様」

玲奈様は微笑みながら、時計をちらりと見る。

「もう遅いわね。帰る準備は?」

彼は軽く伸びをしながら、PCを閉じた。「……そうですね、そろそろ帰ります」

玲奈様は静かに立ち上がり、夜のオフィスを後にした。

彼はデスクに座ったまま、しばらく retain() のコードを思い返していた。
「削除」ではなく、「残す」視点で考える。

これからのコーディングスタイルが、少しだけ変わる気がした。


こうして彼のコードは、よりシンプルに、より効率的に進化した。
玲奈様の教えは、また一つ、彼の中に刻まれた。

いいなと思ったら応援しよう!