🔄
イテレータとクロージャ — Rubyistが最も親しみを感じる領域
select/map/reduceがfilter/map/foldに変わっただけ
Ruby開発者がRustで初めて「おっ、これは馴染みがある」と感じる部分がイテレータだ。
メソッド対応表
| Ruby | Rust | 説明 |
|---|---|---|
each |
for_each |
各要素に実行 |
map |
map |
変換 |
select / filter |
filter |
条件フィルタ |
reject |
`filter(\ | x\ |
reduce / inject |
fold |
累積 |
find |
find |
最初のマッチ |
any? |
any |
1つでも満たす? |
all? |
all |
全て満たす? |
count |
count |
個数 |
flat_map |
flat_map |
平坦化 + 変換 |
zip |
zip |
並列走査 |
take(n) |
take(n) |
先頭n個 |
min / max |
min / max |
最小/最大 |
sum |
sum |
合計 |
sort_by |
sort_by (Vec) |
ソート |
基本チェーン
# Ruby
users.select { |u| u.active? }
.map { |u| u.name }
.sort
// Rust
users.iter()
.filter(|u| u.is_active())
.map(|u| &u.name)
.sorted() // itertools crate必要、またはcollect後にsort
.collect::<Vec<_>>()
核心的な違い:Rustでは最後に.collect()を呼ばないと結果が作られない。イテレータはlazyに動作する。Rubyのlazy列挙子がRustではデフォルト。
クロージャ構文
# Ruby — ブロック
[1, 2, 3].map { |x| x * 2 }
# Ruby — lambda
double = ->(x) { x * 2 }
[1, 2, 3].map(&double)
// Rust — クロージャ
vec![1, 2, 3].iter().map(|x| x * 2).collect::<Vec<_>>();
// 変数に保存
let double = |x: &i32| x * 2;
vec![1, 2, 3].iter().map(double).collect::<Vec<_>>();
{ |x| } → |x|。パイプがブロックの区切りを代替する。
fold — reduceのRust版
# Ruby
[1, 2, 3, 4].reduce(0) { |sum, x| sum + x } # 10
// Rust
vec![1, 2, 3, 4].iter().fold(0, |sum, x| sum + x); // 10
// sum()でもっと簡単に
vec![1, 2, 3, 4].iter().sum::<i32>(); // 10
enumerate — each_with_index
# Ruby
["a", "b", "c"].each_with_index { |item, i| puts "#{i}: #{item}" }
// Rust
vec!["a", "b", "c"].iter().enumerate().for_each(|(i, item)| {
println!("{}: {}", i, item);
});
iter, into_iter, iter_mut
Rubyではeachがあればいい。Rustには3種類のイテレータがある。
iter()— 参照で走査(&T)、元データ維持iter_mut()— 可変参照で走査(&mut T)、元データ変更可能into_iter()— 所有権を取る、元データ使用不可
大抵の場合iter()を使えばいい。
キーポイント
1
select → filter、reduce → fold、each_with_index → enumerate
2
イテレータはlazy — .collect()を呼ばないと結果が出ない
3
クロージャ構文: { |x| } → |x|
4
3種類: iter(参照)、into_iter(所有権)、iter_mut(可変)
メリット
- ✓ Ruby開発者にとって最も直感的なRust機能
- ✓ lazyデフォルト動作で大量データでもメモリ効率的
デメリット
- ✗ .collect()を忘れると何も起こらない
- ✗ iter/into_iter/iter_mutの選択が最初は混乱
ユースケース
データフィルタリング/変換パイプライン
RubyのEnumerableチェーンをRustにポーティングする時