🔄

이터레이터와 클로저 — 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로 포팅할 때