# 이터레이터 소비자(sum, count, etc)

이터레이터 소비자(iterator consumer)는 이터레이터가 제공하는 원소들을 한 번에 전부(혹은 필요에 따라 일부만) 소모하여 최종적인 결과를 산출한다. 이 과정에서 새로운 이터레이터를 반환하지 않고, 마지막에 단일 값 혹은 특정 자료구조를 반환한다. Rust에서 이터레이터는 보통 지연(lazy) 평가를 따르는데, 소비자 메서드를 호출하기 전까지는 실제 연산을 수행하지 않는다. 즉, `.map`이나 `.filter` 같은 이터레이터 어댑터(iterator adapter)는 변환 과정에 불과하며, 최종적으로 소비자 메서드가 호출되어야만 연산이 실행되고 결과가 확정된다.

이터레이터를 소비하는 메서드는 한 번 호출되면 해당 이터레이터는 완전히 소모되어 재사용할 수 없다는 점이 중요하다. 만약 동일한 데이터를 다시 반복해야 할 필요가 있다면, 원본 컬렉션으로부터 다시 이터레이터를 생성하거나, 미리 필요한 데이터를 복제해 두는 방식 등을 고려해야 한다.

이터레이터 소비자로는 sum, count, product, collect, fold, find, any, all, max, min, position 등이 대표적이다. 각 메서드는 보통 다음과 같은 특징이 있다.

sum은 모든 원소의 합계를 구한다. count는 원소의 개수를 세어서 usize로 반환한다. collect는 모든 원소를 특정 컬렉션 타입에 모아 반환한다. fold는 누적(accumulator)을 직접 정의하여 원하는 방식으로 연산을 축적한다. product는 모든 원소의 곱을 구한다. any와 all은 어떤 조건을 만족하는지(또는 모두 만족하는지) 논리값으로 반환한다. find와 position은 조건을 만족하는 첫 번째 원소나 그 위치를 찾는다.

아래에서 중요한 몇 가지 소비자 메서드를 상세하게 살펴본다.

### sum

sum은 이터레이터가 생성하는 모든 원소의 합을 계산해 반환한다. 반환 타입은 이터레이터 원소 타입의 Add 트레이트 구현에 의해 결정된다. 일반적으로 합계를 구할 때 사용하는 정수, 부동소수점 등의 기본 타입에 대해 sum이 구현되어 있지만, 타입 추론이 정확히 되지 않을 경우에는 결과 타입을 명시해 주어야 한다.

```
let numbers = vec![1, 2, 3, 4, 5];

// 결과를 i32로 명시. 
let total: i32 = numbers.iter().sum();
println!("sum: {}", total);
```

소비자 메서드이므로 sum이 호출된 시점에서 모든 원소가 순회된다. 한 번 sum을 호출하면, 그 이터레이터는 재사용할 수 없다.

### count

count는 이터레이터가 생성하는 모든 원소의 개수를 세어 usize 타입으로 반환한다. 원소의 실제 내용이나 값은 고려하지 않고, 순수하게 원소의 수만 측정한다.

```
let numbers = vec![10, 20, 30, 40, 50];
let count = numbers.iter().count();
println!("count: {}", count);
```

이터레이터가 언제까지 유효한지도 count를 통해 확인할 수 있다. 이 메서드를 호출하면 내부적으로 원소가 끝까지 소모된다.

### product

product는 모든 원소의 곱을 구해 반환한다. sum과 마찬가지로 결과 타입은 이터레이터 원소 타입의 Mul 트레이트와 Default, FromIterator 등에 의해 추론되거나 명시되어야 한다.

```
let numbers = vec![1, 2, 3, 4];
let product: i32 = numbers.iter().product();
println!("product: {}", product);
```

결과는 곱셈을 통해 계산되므로, 자료형의 범위를 넘어설 가능성을 주의해야 한다.

### collect

collect는 이터레이터의 모든 원소를 지정된 컬렉션 타입으로 모아 반환한다. 주로 Vec 타입으로 자주 모으지만, HashMap, HashSet, String, 기타 표준 라이브러리의 컬렉션에 대해서도 동일하게 적용할 수 있다.

```
let numbers = 1..=5;
let collected: Vec<i32> = numbers.collect();
println!("{:?}", collected);
```

collect를 호출할 때는 반환하고자 하는 타입을 명시해 주어야 하거나, 컴파일러가 맥락을 통해 추론할 수 있어야 한다. collect 메서드는 이터레이터 원소를 전부 순회하여 새로운 자료구조를 만드는 전형적인 소비자 메서드에 해당한다.

### fold

fold는 누적(accumulator) 변수를 초기값과 함께 제공하고, 각 단계에서 수행할 연산을 클로저(또는 람다)로 정의하여 원하는 결과를 만들어 낸다. sum이나 product와 같은 연산은 fold로도 구현할 수 있으며, 그 외에도 여러 복잡한 로직을 직접 정의해서 사용할 수 있다는 장점이 있다.

```
let numbers = vec![1, 2, 3, 4, 5];
let total = numbers.iter().fold(0, |acc, &x| acc + x);
println!("fold로 계산한 sum: {}", total);
```

초기값(위 예제에서는 0)부터 시작해, 각 원소 x를 acc에 더하여 새로운 누적값을 만든다. sum, product보다 훨씬 유연하게 동작하기 때문에 이터레이터를 활용한 다양한 연산을 정의할 때 자주 사용된다.

### any와 all

any와 all은 이터레이터의 모든 원소 중 특정 조건을 충족하는 원소가 하나라도 있는지(any), 혹은 모두 조건을 충족하는지(all)를 bool로 반환한다.

```
let numbers = vec![1, 2, 3, 4, 5];
let has_even = numbers.iter().any(|&x| x % 2 == 0);
let all_positive = numbers.iter().all(|&x| x > 0);
println!("짝수가 존재하는가? {}", has_even);
println!("모든 원소가 양의 정수인가? {}", all_positive);
```

any나 all 역시 조건을 판단하기 위해 원소를 순회하면서 조건을 만족하는 시점에 순회가 중단될 수 있다(예: any는 조건을 만족하는 원소를 찾는 즉시 true를 반환하고 이터레이션을 멈춤).

### find와 position

find는 특정 조건을 만족하는 첫 번째 원소의 참조를 Some(T) 형태로 반환하거나, 없다면 None을 반환한다. position은 조건을 만족하는 첫 번째 원소의 인덱스를 Some(usize)로 반환하거나, 없다면 None을 반환한다.

```
let numbers = vec![3, 6, 9, 12, 15];
let multiple_of_four = numbers.iter().find(|&&x| x % 4 == 0);
let position_of_multiple_of_four = numbers.iter().position(|&x| x % 4 == 0);

match multiple_of_four {
    Some(&n) => println!("4의 배수를 찾았다: {}", n),
    None => println!("4의 배수가 없다."),
}
match position_of_multiple_of_four {
    Some(idx) => println!("4의 배수는 인덱스 {}에 위치한다.", idx),
    None => println!("4의 배수가 없다."),
}
```

이터레이터가 내부적으로 순회를 진행하기 때문에, 원하는 원소를 찾는 즉시 소비가 완료되거나, 전체를 순회한 뒤 None을 반환하기도 한다.

이터레이터 소비자 메서드는 이처럼 다양한 상황에서 유용하게 쓰이며, Rust의 이터레이터 패턴을 완성하는 중요한 요소다. 이터레이터 어댑터가 가진 “지연성”은 실제 연산 결과가 필요할 때까지 계산을 미루는 장점을 제공하고, 소비자 메서드를 통해 효율적인 순회와 계산을 수행할 수 있게 된다. 한 번 소비된 이터레이터는 재활용할 수 없다는 점만 유의한다면, sum, count, collect, fold 같은 소비자 메서드는 간결하고 직관적인 코드를 작성하는 데 매우 유리하다.
