Prompt
Iteratorのcollectメソッドってどうやって使うんだ?
おっ、ついにRustのイテレータにおける「最強の締めくくり役」である collect にたどり着いたね!
collect は、イテレータという「データの流れ」を、Vec や HashMap といった「具体的なコレクション」に一気に流し込んで固めるメソッドだよ。
情報工学を学ぶ君のために、その魔法のような仕組みと使い方を整理するぜ!🚀
1. 🔑 collect の一番のルール:型指定が必要!
collect は非常に多才で、同じイテレータから Vec にもなれるし、HashSet にもなれる。だから、コンパイラに**「何に変換したいか」**を教えてあげないといけないんだ。
一番よく使う、もっとも確実な書き方はこれだ!
Rust
let v = vec![1, 2, 3];
// 1. 変数の型を明示する(こっちがオススメ)
let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();
// 2. ターボフィッシュ演算子 ::<> を使う(通な書き方)
let doubled = v.iter().map(|x| x * 2).collect::<Vec<i32>>();💡 豆知識:ターボフィッシュ ::<>
::<> という形が魚(サカナ)に見えるからそう呼ばれているんだ。Rust特有の可愛い呼び名だよね!
2. 🗺️ HashMap への変換
collect は Vec だけじゃない! (キー, 値) のペア(タプル)のイテレータからなら、HashMap も作れるんだ。
Rust
use std::collections::HashMap;
let fruits = vec![("apple", 100), ("banana", 200)];
// タプルのイテレータを HashMap に変換!
let fruit_map: HashMap<&str, i32> = fruits.into_iter().collect();
println!("{:?}", fruit_map); // {"apple": 100, "banana": 200}3. 🛡️ Result や Option をまるごと collect する(超便利!)
これこそが Rust の collect が「神」と言われる理由の一つだ。
「もし一つでもエラーがあったら失敗、全部成功なら Vec にする」 という処理が一瞬で書けるんだ!
Rust
let strings = vec!["10", "20", "invalid", "40"];
// parse() は Result を返す。
// Result<Vec<u32>, _> 型に collect すると...
let results: Result<Vec<u32>, _> = strings.iter()
.map(|s| s.parse::<u32>())
.collect();
// 途中に "invalid" があるから、results は Err になる!
// 全部数字なら Ok(Vec) になる。超賢い!4. 🧠 なぜ collect はこんなに賢いのか?(情報工学的視点)
collect の裏側には FromIterator というトレイトがあるんだ。
-
collectを呼ぶ。 -
コンパイラが「あ、この人は
Vec<i32>を欲しがってるな」と判断する。 -
Vec<i32>が実装しているFromIteratorのfrom_iter関数が呼び出される。 -
その関数の中で、イテレータをループして
pushする処理が動く。
つまり、**「受け皿側が作り方を決める」**という設計になっているんだ。これによって、新しいコレクションを自作したときも、FromIterator さえ実装すれば collect が使えるようになる。拡張性がバツグンだよね!
⚠️ 落とし穴:無限イテレータ
Rust には (0..).map(…) のように、終わりがない無限イテレータも作れる。
そんなイテレータに対して collect を呼ぶと、メモリを使い果たしてパニックするか、永遠に終わらないから注意だぜ!必ず .take(10) とかで制限をつけてから collect しよう!
どうだい? collect があれば、複雑なデータの詰め替えもワンラインで書けるようになる。まさに Rust プログラミングの醍醐味だよね!
次は、この collect を使った具体的なアルゴリズムや、もっと変態的な(?)イテレータの組み合わせに挑戦してみる?😊✨