Rust Iterator ์ธํ„ฐํŽ˜์ด์Šค ์ข…ํ•ฉ

1. ํ•ต์‹ฌ ํŠธ๋ ˆ์ดํŠธ

Iterator ํŠธ๋ ˆ์ดํŠธ

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    // ... ์—ฌ๋Ÿฌ ๊ธฐ๋ณธ ๊ตฌํ˜„ ๋ฉ”์„œ๋“œ๋“ค
}

IntoIterator ํŠธ๋ ˆ์ดํŠธ

pub trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;
    fn into_iter(self) -> Self::IntoIter;
}

FromIterator ํŠธ๋ ˆ์ดํŠธ

pub trait FromIterator<A> {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = A>;
}

2. ๋ฐ˜๋ณต์ž ์ƒ์„ฑ ๋ฉ”์„œ๋“œ

๊ธฐ๋ณธ ์ปฌ๋ ‰์…˜ ๋ฐ˜๋ณต์ž

  • iter(): ๋ถˆ๋ณ€ ์ฐธ์กฐ ๋ฐ˜๋ณต์ž (&T)
  • iter_mut(): ๊ฐ€๋ณ€ ์ฐธ์กฐ ๋ฐ˜๋ณต์ž (&mut T)
  • into_iter(): ์†Œ์œ ๊ถŒ ์ด์ „ ๋ฐ˜๋ณต์ž (T)

๋ฒ”์œ„ ๋ฐ˜๋ณต์ž

// ๋ฒ”์œ„ ๋ฌธ๋ฒ•์œผ๋กœ ๋ฐ˜๋ณต์ž ์ƒ์„ฑ
let range = 1..5;        // 1, 2, 3, 4
let inclusive = 1..=5;   // 1, 2, 3, 4, 5

์ŠคํŠธ๋ฆผ ๋ฐ˜๋ณต์ž

  • std::io::Lines: ํŒŒ์ผ์˜ ๊ฐ ์ค„์„ ์ˆœํšŒ
  • std::io::Bytes: ๋ฐ”์ดํŠธ ์ŠคํŠธ๋ฆผ์„ ์ˆœํšŒ

๊ธฐํƒ€ ๋ฐ˜๋ณต์ž ์ƒ์„ฑ

  • once: ๋‹จ์ผ ๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐ˜๋ณต์ž
use std::iter;
let once = iter::once(42);  // 42๋งŒ ์ƒ์„ฑ
  • repeat: ๋™์ผํ•œ ๊ฐ’์„ ๋ฌดํ•œํžˆ ์ƒ์„ฑํ•˜๋Š” ๋ฐ˜๋ณต์ž
let repeat = iter::repeat('a');  // 'a'๋ฅผ ๋ฌดํ•œํžˆ ์ƒ์„ฑ
  • empty: ๋นˆ ๋ฐ˜๋ณต์ž
let empty: iter::Empty<i32> = iter::empty();  // ํ•ญ๋ชฉ ์—†์Œ

3. ๋ฐ˜๋ณต์ž ์–ด๋Œ‘ํ„ฐ ๋ฉ”์„œ๋“œ (์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๋“ค)

ํ•„ํ„ฐ๋ง ์–ด๋Œ‘ํ„ฐ

  • filter(pred): ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ํ•ญ๋ชฉ๋งŒ ์œ ์ง€
  • filter_map(f): ๋ณ€ํ™˜๊ณผ ํ•„ํ„ฐ๋ง์„ ๋™์‹œ์— ์ˆ˜ํ–‰
  • take(n): ์ฒ˜์Œ n๊ฐœ ํ•ญ๋ชฉ๋งŒ ์œ ์ง€
  • take_while(pred): ์กฐ๊ฑด์ด ์ฐธ์ธ ๋™์•ˆ์˜ ํ•ญ๋ชฉ๋งŒ ์œ ์ง€
  • skip(n): ์ฒ˜์Œ n๊ฐœ ํ•ญ๋ชฉ์„ ๊ฑด๋„ˆ๋œ€
  • skip_while(pred): ์กฐ๊ฑด์ด ์ฐธ์ธ ๋™์•ˆ ํ•ญ๋ชฉ์„ ๊ฑด๋„ˆ๋œ€
  • step_by(n): n ๋‹จ๊ณ„๋งˆ๋‹ค ํ•ญ๋ชฉ์„ ์„ ํƒ
  • peekable(): ๋‹ค์Œ ํ•ญ๋ชฉ์„ ๋ฏธ๋ฆฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ณต์ž ์ƒ์„ฑ

๋ณ€ํ™˜ ์–ด๋Œ‘ํ„ฐ

  • map(f): ๊ฐ ํ•ญ๋ชฉ์„ ๋ณ€ํ™˜
  • flat_map(f): ์ค‘์ฒฉ ๋ฐ˜๋ณต์ž๋ฅผ ํ‰ํƒ„ํ™”
  • flatten(): ์ค‘์ฒฉ๋œ ๋ฐ˜๋ณต์ž๋ฅผ ํ•œ ์ˆ˜์ค€ ํ‰ํƒ„ํ™”
  • inspect(f): ๊ฐ ํ•ญ๋ชฉ์„ ๊ฒ€์‚ฌ (๋””๋ฒ„๊น…์šฉ)
  • cloned(): ์ฐธ์กฐ ๋ฐ˜๋ณต์ž์˜ ๊ฐ’์„ ๋ณต์ œ
  • copied(): ๋ณต์‚ฌ ๊ฐ€๋Šฅํ•œ ์ฐธ์กฐ ๋ฐ˜๋ณต์ž์˜ ๊ฐ’์„ ๋ณต์‚ฌ
  • map_while(f): ์กฐ๊ฑด์ด ์ฐธ์ธ ๋™์•ˆ ๋ณ€ํ™˜
  • scan(state, f): ์ƒํƒœ๋ฅผ ๊ฐ€์ง„ ๋ณ€ํ™˜

๊ฒฐํ•ฉ ์–ด๋Œ‘ํ„ฐ

  • chain(other): ๋‘ ๋ฐ˜๋ณต์ž๋ฅผ ์—ฐ๊ฒฐ
  • zip(other): ๋‘ ๋ฐ˜๋ณต์ž๋ฅผ ์Œ์œผ๋กœ ๊ฒฐํ•ฉ
  • unzip(): ์Œ์˜ ๋ฐ˜๋ณต์ž๋ฅผ ๋‘ ๊ฐœ๋กœ ๋ถ„๋ฆฌ
  • enumerate(): ์ธ๋ฑ์Šค์™€ ๊ฐ’์˜ ์Œ์œผ๋กœ ๋ณ€ํ™˜
  • partition(pred): ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„๋ฆฌ

์ˆœ์„œ ๊ด€๋ จ ์–ด๋Œ‘ํ„ฐ

  • rev(): ๋ฐ˜๋ณต์ž์˜ ์ˆœ์„œ๋ฅผ ๋’ค์ง‘์Œ (์–‘๋ฐฉํ–ฅ ๋ฐ˜๋ณต์ž์—๋งŒ ์ ์šฉ ๊ฐ€๋Šฅ)
  • cycle(): ๋ฐ˜๋ณต์ž๋ฅผ ๋ฌดํ•œํžˆ ๋ฐ˜๋ณต
  • interleave(other): ๋‘ ๋ฐ˜๋ณต์ž์˜ ํ•ญ๋ชฉ์„ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉฐ ์ƒ์„ฑ
  • interleave_shortest(other): ๋” ์งง์€ ๋ฐ˜๋ณต์ž๊นŒ์ง€๋งŒ ๋ฒˆ๊ฐˆ์•„๊ฐ€๋ฉฐ ์ƒ์„ฑ

๊ทธ๋ฃนํ™” ์–ด๋Œ‘ํ„ฐ

  • chunks(n): n๊ฐœ ํ•ญ๋ชฉ์˜ ์ฒญํฌ๋กœ ๊ทธ๋ฃนํ™”
  • chunks_exact(n): ์ •ํ™•ํžˆ n๊ฐœ ํ•ญ๋ชฉ์˜ ์ฒญํฌ๋กœ ๊ทธ๋ฃนํ™”
  • windows(n): n๊ฐœ ํ•ญ๋ชฉ์˜ ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ๋กœ ๊ทธ๋ฃนํ™”

4. ๋ฐ˜๋ณต์ž ์†Œ๋น„์ž ๋ฉ”์„œ๋“œ

์ปฌ๋ ‰์…˜ ๋ณ€ํ™˜

  • collect(): ๋ฐ˜๋ณต์ž๋ฅผ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋ณ€ํ™˜
let v: Vec<i32> = (0..5).collect();
let s: HashSet<i32> = (0..5).collect();
let m: HashMap<char, i32> = vec![('a', 1), ('b', 2)].into_iter().collect();

๊ณ„์‚ฐ ์†Œ๋น„์ž

  • sum(): ๋ชจ๋“  ํ•ญ๋ชฉ์˜ ํ•ฉ๊ณ„๋ฅผ ๊ณ„์‚ฐ
  • product(): ๋ชจ๋“  ํ•ญ๋ชฉ์˜ ๊ณฑ์„ ๊ณ„์‚ฐ
  • fold(init, f): ์ดˆ๊ธฐ๊ฐ’๊ณผ ํ•จ์ˆ˜๋กœ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ์ ‘์Œ
  • reduce(f): ์ฒซ ํ•ญ๋ชฉ์„ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘์Œ
  • try_fold(init, f): ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ fold
  • try_reduce(f): ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ reduce

๊ฒ€์ƒ‰ ์†Œ๋น„์ž

  • find(pred): ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ํ•ญ๋ชฉ์„ ์ฐพ์Œ
  • position(pred): ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ํ•ญ๋ชฉ์˜ ์œ„์น˜๋ฅผ ์ฐพ์Œ
  • rposition(pred): ๋’ค์—์„œ๋ถ€ํ„ฐ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ํ•ญ๋ชฉ์˜ ์œ„์น˜๋ฅผ ์ฐพ์Œ
  • contains(&x): ํŠน์ • ํ•ญ๋ชฉ์„ ํฌํ•จํ•˜๋Š”์ง€ ํ™•์ธ
  • any(pred): ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ํ•ญ๋ชฉ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
  • all(pred): ๋ชจ๋“  ํ•ญ๋ชฉ์ด ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธ
  • max(): ์ตœ๋Œ€ ํ•ญ๋ชฉ์„ ์ฐพ์Œ
  • min(): ์ตœ์†Œ ํ•ญ๋ชฉ์„ ์ฐพ์Œ
  • max_by(cmp): ๋น„๊ต ํ•จ์ˆ˜๋กœ ์ตœ๋Œ€ ํ•ญ๋ชฉ์„ ์ฐพ์Œ
  • min_by(cmp): ๋น„๊ต ํ•จ์ˆ˜๋กœ ์ตœ์†Œ ํ•ญ๋ชฉ์„ ์ฐพ์Œ
  • max_by_key(f): ํ‚ค ํ•จ์ˆ˜๋กœ ์ตœ๋Œ€ ํ•ญ๋ชฉ์„ ์ฐพ์Œ
  • min_by_key(f): ํ‚ค ํ•จ์ˆ˜๋กœ ์ตœ์†Œ ํ•ญ๋ชฉ์„ ์ฐพ์Œ

๊ธฐํƒ€ ์†Œ๋น„์ž

  • count(): ํ•ญ๋ชฉ์˜ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜
  • last(): ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์„ ๋ฐ˜ํ™˜
  • nth(n): n๋ฒˆ์งธ ํ•ญ๋ชฉ์„ ๋ฐ˜ํ™˜
  • for_each(f): ๊ฐ ํ•ญ๋ชฉ์— ํ•จ์ˆ˜๋ฅผ ์ ์šฉ
  • try_for_each(f): ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ for_each
  • is_partitioned(pred): ๋ฐ˜๋ณต์ž๊ฐ€ ๋ถ„ํ• ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
  • is_sorted(): ๋ฐ˜๋ณต์ž๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
  • is_sorted_by(cmp): ๋น„๊ต ํ•จ์ˆ˜๋กœ ์ •๋ ฌ ์—ฌ๋ถ€ ํ™•์ธ

5. ํŠน์ˆ˜ ๋ฐ˜๋ณต์ž ์œ ํ˜•

Peekable

๋‹ค์Œ ํ•ญ๋ชฉ์„ ์†Œ๋น„ํ•˜์ง€ ์•Š๊ณ  ๋ฏธ๋ฆฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ณต์ž:

let mut peekable = [1, 2, 3].iter().peekable();
if let Some(&first) = peekable.peek() {
    println!("๋‹ค์Œ ํ•ญ๋ชฉ: {}", first);
}

Fuse

None์„ ๋ฐ˜ํ™˜ํ•œ ์ดํ›„ ํ•ญ์ƒ None์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ๋ฐ˜๋ณต์ž:

let fused = [1, 2, 3].iter().fuse();

Cycle

๋ฐ˜๋ณต์ž๋ฅผ ๋ฌดํ•œํžˆ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐ˜๋ณต์ž:

let mut cycle = [1, 2, 3].iter().cycle();
// 1, 2, 3, 1, 2, 3, ...

Enumerate

์ธ๋ฑ์Šค์™€ ๊ฐ’์˜ ์Œ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋ฐ˜๋ณต์ž:

let enumerated = ['a', 'b', 'c'].iter().enumerate();
// (0, 'a'), (1, 'b'), (2, 'c')

Chain

๋‘ ๋ฐ˜๋ณต์ž๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ˜๋ณต์ž:

let chained = [1, 2].iter().chain([3, 4].iter());
// 1, 2, 3, 4

Zip

๋‘ ๋ฐ˜๋ณต์ž๋ฅผ ์Œ์œผ๋กœ ๋ฌถ๋Š” ๋ฐ˜๋ณต์ž:

let zipped = [1, 2].iter().zip(['a', 'b'].iter());
// (1, 'a'), (2, 'b')

6. ๊ตฌํ˜„ ํŒจํ„ด

์ปฌ๋ ‰์…˜์— ๋ฐ˜๋ณต์ž ๊ตฌํ˜„ํ•˜๊ธฐ

struct MyCollection<T> {
    data: Vec<T>,
}

impl<T> MyCollection<T> {
    fn iter(&self) -> impl Iterator<Item = &T> {
        self.data.iter()
    }
    
    fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
        self.data.iter_mut()
    }
}

impl<T> IntoIterator for MyCollection<T> {
    type Item = T;
    type IntoIter = std::vec::IntoIter<T>;
    
    fn into_iter(self) -> Self::IntoIter {
        self.data.into_iter()
    }
}

impl<'a, T> IntoIterator for &'a MyCollection<T> {
    type Item = &'a T;
    type IntoIter = std::slice::Iter<'a, T>;
    
    fn into_iter(self) -> Self::IntoIter {
        self.data.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut MyCollection<T> {
    type Item = &'a mut T;
    type IntoIter = std::slice::IterMut<'a, T>;
    
    fn into_iter(self) -> Self::IntoIter {
        self.data.iter_mut()
    }
}

์‚ฌ์šฉ์ž ์ •์˜ ๋ฐ˜๋ณต์ž ๊ตฌํ˜„ํ•˜๊ธฐ

struct Fibonacci {
    curr: u32,
    next: u32,
}

impl Fibonacci {
    fn new() -> Fibonacci {
        Fibonacci { curr: 0, next: 1 }
    }
}

impl Iterator for Fibonacci {
    type Item = u32;
    
    fn next(&mut self) -> Option<Self::Item> {
        let new_next = self.curr + self.next;
        self.curr = self.next;
        self.next = new_next;
        Some(self.curr)
    }
}

7. ์œ ์šฉํ•œ ํŒจํ„ด๊ณผ ๊ธฐ๋ฒ•

์ปฌ๋ ‰์…˜ ๋ณ€ํ™˜ํ•˜๊ธฐ

// Vec<T> -> Vec<U>
let v: Vec<i32> = vec![1, 2, 3];
let doubled: Vec<i32> = v.iter().map(|&x| x * 2).collect();

// Vec<T> -> HashSet<T>
let set: HashSet<i32> = v.iter().cloned().collect();

// Vec<T> -> HashMap<K, V>
let map: HashMap<i32, char> = vec![(1, 'a'), (2, 'b')].into_iter().collect();

๊ทธ๋ฃนํ™” ๋ฐ ํ•„ํ„ฐ๋ง

// ์ง์ˆ˜์™€ ํ™€์ˆ˜๋กœ ๊ทธ๋ฃนํ™”
let (even, odd): (Vec<i32>, Vec<i32>) = (1..=10).partition(|&n| n % 2 == 0);

// ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ•„ํ„ฐ๋ง
let positive: Vec<i32> = vec![-1, 2, -3, 4].into_iter().filter(|&x| x > 0).collect();

Result์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ

// ๋ชจ๋“  ๊ฒฐ๊ณผ๊ฐ€ Ok์ธ์ง€ ํ™•์ธ
let results = vec![Ok(1), Ok(2), Ok(3)];
let all_ok = results.iter().all(|r| r.is_ok());

// Ok ๊ฐ’๋งŒ ์ˆ˜์ง‘
let ok_values: Vec<i32> = results.into_iter().filter_map(Result::ok).collect();

Option๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ

// Some ๊ฐ’๋งŒ ์ˆ˜์ง‘
let options = vec![Some(1), None, Some(2)];
let values: Vec<i32> = options.into_iter().filter_map(|o| o).collect();

์ค‘์ฒฉ ๊ตฌ์กฐ ์ฒ˜๋ฆฌํ•˜๊ธฐ

// ์ค‘์ฒฉ ๋ฐ˜๋ณต์ž ํ‰ํƒ„ํ™”
let nested = vec![vec![1, 2], vec![3, 4]];
let flat: Vec<i32> = nested.into_iter().flatten().collect();  // [1, 2, 3, 4]

// map๊ณผ flatten ์กฐํ•ฉ
let words = vec!["hello", "world"];
let chars: Vec<char> = words.iter()
    .flat_map(|word| word.chars())
    .collect();  // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']

์ˆœ์ฐจ ์ฒ˜๋ฆฌ vs ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ

// ์ˆœ์ฐจ ์ฒ˜๋ฆฌ (ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)
let sum: i32 = (1..1000).sum();

// ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ (rayon ํฌ๋ ˆ์ดํŠธ ์‚ฌ์šฉ)
use rayon::prelude::*;
let sum: i32 = (1..1000).into_par_iter().sum();

๋ฌดํ•œ ๋ฐ˜๋ณต์ž ๋‹ค๋ฃจ๊ธฐ

// ๋ฌดํ•œ ๋ฐ˜๋ณต์ž ์ƒ์„ฑ
let infinite = std::iter::repeat(1);

// ์œ ํ•œ ๋ฐ˜๋ณต์ž๋กœ ์ œํ•œ
let finite: Vec<i32> = infinite.take(5).collect();  // [1, 1, 1, 1, 1]

8. ์™ธ๋ถ€ ํฌ๋ ˆ์ดํŠธ์˜ ๋ฐ˜๋ณต์ž ํ™•์žฅ

Itertools ํฌ๋ ˆ์ดํŠธ

Itertools๋Š” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ฐ˜๋ณต์ž ๊ธฐ๋Šฅ์„ ํ™•์žฅ:

use itertools::Itertools;

// ๊ทธ๋ฃนํ™”
let groups = vec![1, 1, 1, 3, 3, 2, 2, 2]
    .into_iter()
    .group_by(|&x| x);

// ์ˆœ์—ด
let permutations = [1, 2, 3].iter().permutations(2);

// ์กฐํ•ฉ
let combinations = [1, 2, 3, 4].iter().combinations(2);

// intersperse
let interspersed: Vec<i32> = [1, 2, 3].iter()
    .cloned()
    .intersperse(0)
    .collect();  // [1, 0, 2, 0, 3]

// ์ค‘๋ณต ํ•ญ๋ชฉ ์ œ๊ฑฐ
let unique: Vec<i32> = [1, 2, 1, 3, 2].iter()
    .cloned()
    .unique()
    .collect();  // [1, 2, 3]

Rayon ํฌ๋ ˆ์ดํŠธ

Rayon์€ ๋ณ‘๋ ฌ ๋ฐ˜๋ณต์ž ์ œ๊ณต:

use rayon::prelude::*;

// ๋ณ‘๋ ฌ ๋งต
let v: Vec<i32> = (0..1000)
    .into_par_iter()
    .map(|i| i * i)
    .collect();

// ๋ณ‘๋ ฌ ํ•„ํ„ฐ
let evens: Vec<i32> = (0..1000)
    .into_par_iter()
    .filter(|i| i % 2 == 0)
    .collect();