🔄
이터레이터와 클로저 — 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 |
하나라도 만족? |
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에는 세 종류의 이터레이터가 있다.
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
iter(참조), into_iter(소유권), iter_mut(가변) 세 종류
장점
- ✓ Ruby 개발자에게 가장 직관적인 Rust 기능
- ✓ lazy 기본 동작으로 대량 데이터에서도 메모리 효율적
단점
- ✗ .collect() 잊으면 아무 일도 안 일어난다
- ✗ iter/into_iter/iter_mut 선택이 초반에 혼란
사용 사례
데이터 필터링/변환 파이프라인
Ruby의 Enumerable 체이닝을 Rust로 포팅할 때