# Option, Iterator, Clone, Copy

러스트에서 값의 유무를 안전하게 표현하기 위해 사용되는 Option 타입은 매우 중요한 개념이다. 이 타입은 None과 Some(T)라는 두 가지 분기로 구성된 열거형이며, 값이 없을 수 있는 상황을 명시적으로 표현하기 때문에 런타임 오류를 줄이는 데 큰 도움이 된다. 예를 들어 어떤 함수가 검색 결과로 실제 값이 없을 수 있다면 Option을 반환해 의도적으로 None을 반환하도록 만들 수 있다. None에 대한 처리를 컴파일 타임에 강제하기 때문에 안전한 프로그래밍을 유도한다.

Option 타입을 사용할 때는 match 구문을 많이 사용한다. Rust의 패턴 매칭은 매우 강력하며, 각 케이스에 대해 구체적으로 명시할 수 있다. 값이 있을 때(Some)와 없을 때(None)에 대한 처리가 코드 상에서 모두 드러나기 때문에 코드의 가독성과 안전성이 향상된다. 또한 Option에는 메서드 체이닝을 활용할 수 있는 각종 헬퍼 메서드가 많이 제공된다. 예를 들어 unwrap\_or, map, and\_then 같은 메서드를 통해 match를 직접 작성하지 않고도 간단한 로직 처리를 할 수 있다. 그러나 안전성을 중시하기 위해서는 match 구문 혹은 적절한 메서드를 사용하는 편이 좋다.

아래 코드는 Option을 활용하는 예시이며, None인 경우와 Some인 경우를 나누어 처리하는 모습을 보여준다.

```
fn find_even_number(numbers: &[i32]) -> Option<i32> {
    for &num in numbers {
        if num % 2 == 0 {
            return Some(num);
        }
    }
    None
}

fn main() {
    let list = vec![1, 3, 5, 8, 10];
    let result = find_even_number(&list);

    match result {
        Some(val) => println!("짝수를 찾았다: {}", val),
        None => println!("짝수를 찾지 못하였다"),
    }

    let default_number = result.unwrap_or(-1);
    println!("결과가 없으면 -1을 사용한다: {}", default_number);
}
```

Iterator는 컬렉션이나 그 외 반복 가능한 구조에서 요소를 순회하기 위한 핵심 기능이다. 러스트의 Iterator 트레이트는 next 메서드를 사용하여 반복 시마다 다음 값을 반환한다. next가 None을 반환하면 반복이 종료된다. 반복자는 소유권, 참조, 가변 참조 등 다양한 형태의 이터레이터를 제공하며, 이 때 소모성(consume) 메서드와 반소모성(adapt) 메서드를 적절히 구분해서 사용하는 방식이 유용하다. 예를 들어 collect, fold, find 같은 메서드는 이터레이터를 소모하면서 결과를 만들어내고, map, filter, take와 같은 메서드는 이터레이터를 다른 이터레이터로 변환하며 계속 체이닝할 수 있다.

이터레이터는 for 루프에서도 자주 활용된다. for 루프는 내부적으로 Iterator 트레이트를 사용해 순회한다. 따라서 rust에서 for ... in 구문을 사용할 수 있는 모든 자료구조는 결국 Iterator를 구현하고 있다고 보면 된다. 아래는 이터레이터 메서드를 체이닝하여 필터링과 맵핑을 거친 뒤 최종적으로 벡터로 수집하는 예시다.

```
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6];
    let processed = numbers
        .iter()
        .filter(|&&x| x % 2 == 0)
        .map(|&x| x * x)
        .collect::<Vec<i32>>();

    println!("짝수만 골라 제곱한 결과: {:?}", processed);
}
```

Clone은 일반적으로 “복제”가 필요한 타입에 구현되는 트레이트다. Clone 트레이트를 구현하면 .clone() 메서드를 통해 객체의 상태를 그대로 복사할 수 있다. 그러나 Rust에서 깊은 복사(deep copy)가 일어날 때 드는 비용에 대해 프로그래머가 명시적으로 인지하게 하려는 의도가 있기 때문에, Clone을 호출해야만 객체가 복제된다는 사실을 명확히 표현한다. 예를 들어 벡터, 문자열(String), 사용자 정의 구조체 등은 Clone을 통해 복사할 때 새로운 메모리를 할당하거나 내부 데이터를 전부 복제해야 한다.

Clone 트레이트를 구현하는 타입은 별도의 로직으로 복제를 제어할 수도 있다. 예를 들어 어떤 구조체 내에 복제 비용이 큰 필드가 있다면, Clone 구현에서 그것을 어떻게 복제할지 세부적으로 정의할 수 있다. 기본적인 Clone 파생(derive)도 가능하지만, 복잡한 객체라면 수동 구현이 필요할 수도 있다.

```
#[derive(Clone)]
struct Data {
    values: Vec<i32>,
    name: String,
}

fn main() {
    let original = Data {
        values: vec![1, 2, 3],
        name: "example".to_string(),
    };
    let copy = original.clone();

    println!("원본: {:?}", original.values);
    println!("복제본: {:?}", copy.values);
}
```

Copy는 Clone과 다르게 “깊은 복사”가 아닌 “비트 단위 복사”를 의미하는 트레이트이자 마커 트레이트다. Copy를 구현할 수 있는 타입은 런타임 복사 비용이 무시할 수 있을 정도로 작으며, 대부분 스택에 직접 배치되는 데이터이다. i32, f64 같은 기본 정수, 부동소수점, 불리언 등이 대표적으로 Copy 타입이다. Copy 트레이트가 적용된 타입은 변수 이동이 발생하지 않고 복사가 자연스럽게 일어난다. 즉, Copy가 가능한 타입의 값을 다른 변수에 대입해도 원본 변수가 유효성을 상실하지 않는다.

Copy는 Clone을 상속하는 구조이므로 Copy 트레이트가 적용된 타입은 자동으로 Clone도 구현하지만, Copy 트레이트가 적용되는 순간 .clone() 메서드는 굳이 호출할 필요가 없어진다. Copy 트레이트를 적용하려면 타입 내부에 참조 타입이나 소유권이 발생할 수 있는 필드 등이 없어야 한다. 따라서 Vec이나 String처럼 힙을 사용하는 타입은 Copy가 불가능하고 Clone만 가능하다. Copy와 Clone의 차이를 정확히 이해하면 Rust의 메모리 모델을 더욱 안전하고 효율적으로 활용할 수 있다.

아래 예시에서는 i32는 Copy 타입이므로 값이 그대로 복사되어 a, b 변수가 모두 유효하다. Vec는 Copy가 불가능한 타입이므로 이동이 발생하며, 이동 후 원본 변수를 사용하려고 하면 컴파일 에러가 난다.

```
fn main() {
    let x: i32 = 10;
    let y = x; // i32는 Copy 타입, x의 값이 y로 복사됨
    println!("x: {}, y: {}", x, y); // 둘 다 사용 가능

    let v: Vec<i32> = vec![1, 2, 3];
    let w = v; // Vec은 Copy가 아니므로 이동 발생
    // println!("{:?}", v); // 컴파일 에러: v는 더 이상 유효하지 않음
    println!("{:?}", w);
}
```

Option, Iterator, Clone, Copy는 모두 Rust의 안전한 메모리 모델과 관련된 중요한 구성 요소들이다. Option으로 값의 존재 여부를 엄격하게 다루고, Iterator로 컬렉션의 요소를 효율적으로 순회하며, Clone과 Copy를 통해 복제 정책을 명확히 구분함으로써 런타임 오류를 줄이고 성능 저하를 최소화할 수 있다. 이러한 표준 라이브러리와 트레이트의 설계는 Rust를 안전하면서도 빠른 언어로 만드는 큰 기반이 된다.
