# 분기에서의 패턴 매칭 활용

Rust에서 패턴 매칭은 단순히 하나의 값을 조건에 따라 여러 갈래로 분기하는 것을 넘어, 복합 자료구조를 효율적으로 구조 분해하고 해당 분기를 보다 엄밀하게 처리할 수 있게 해준다. 열거형(Enums)과 구조체(Struct)를 다양하게 섞어 쓰면서 중첩된 데이터를 간결하게 다루려면 패턴 매칭이 필수적이다. 특히 분기문에서 패턴 매칭을 적절히 활용하면 코드 가독성과 안전성을 높일 수 있다.

match 표현식은 특정 값이 주어진 경우의 수 중 어느 것과 일치하는지(또는 일치하지 않는지)를 검사해 분기하는 가장 대표적인 구문이다. 열거형과 구조체, 튜플, 배열 등 다양한 형태의 데이터 구조를 match 안에서 직접 분해할 수 있으며, 원하는 로직을 각 케이스에 따라 세분화해 작성할 수 있다. 예를 들어, Option 형태의 값을 match로 분기해 None인 경우와 Some(...)인 경우 각각을 명확히 처리할 수 있고, Some(...) 내부 값만 바로 꺼내 쓸 수도 있다.

아래는 Option 열거형을 match로 분기하여 값을 추출하고 처리하는 간단한 예시이다.

```rust
fn process_option(value: Option<i32>) {
    match value {
        Some(v) => {
            println!("값이 있다: {}", v);
        }
        None => {
            println!("값이 없다.");
        }
    }
}

fn main() {
    let a = Some(10);
    let b = None;
    process_option(a);
    process_option(b);
}
```

열거형이 여러 변형(variant)을 지니는 상황에서는 match가 더욱 효과적이다. 예를 들어, Result\<T, E> 타입에서 성공(Ok)과 실패(Err)를 구분할 때나, 직접 만든 열거형에서 각 변형의 종류별로 상세한 처리를 해야 할 때 match 패턴 매칭이 두드러진 장점을 발휘한다. 패턴을 활용하면 단순 변형 분기뿐 아니라 내부 값까지 바로 추출할 수 있다.

```rust
enum Response {
    Success(u32),
    Error(String),
    Unknown,
}

fn handle_response(resp: Response) {
    match resp {
        Response::Success(code) => {
            println!("성공 코드: {}", code);
        }
        Response::Error(msg) => {
            println!("오류 메시지: {}", msg);
        }
        Response::Unknown => {
            println!("알 수 없는 상태이다.");
        }
    }
}

fn main() {
    handle_response(Response::Success(200));
    handle_response(Response::Error("네트워크 오류".to_string()));
    handle_response(Response::Unknown);
}
```

match를 사용하면 모든 변형을 반드시 처리하도록 강제하기 때문에, 컴파일러가 누락된 분기 처리를 잡아줄 수 있다는 이점이 있다. 이와 달리, if let 또는 while let 구문은 특정 패턴만 간단히 처리하고, 나머지 경우는 자동으로 무시하거나 다른 로직으로 분기하고 싶을 때 주로 사용한다. 즉, if let은 원하는 특정 패턴과 일치하는지 확인하고, 일치한다면 내부 로직으로 진입한다. 일치하지 않으면 else 블록(있다면)으로 넘어간다.

아래 예시에서 if let을 사용해 Option 타입이 Some이면 내부 값을 꺼낸 뒤 처리하고, 그렇지 않으면 별도의 로직을 수행한다.

```rust
fn example_if_let(value: Option<i32>) {
    if let Some(v) = value {
        println!("값을 찾았다: {}", v);
    } else {
        println!("값이 없다.");
    }
}

fn main() {
    example_if_let(Some(42));
    example_if_let(None);
}
```

단일 분기에 대해서만 간단히 처리하고, 나머지 모든 패턴은 별도로 구분할 필요가 없을 때 if let을 사용하면 코드가 좀 더 간결해진다. 패턴이 하나 이상이며 모든 패턴을 명시해야 한다면 match를 사용하는 편이 좋다. 여러 가지 분기 로직이 필요한 상황에서 if let을 중첩하면 오히려 가독성이 떨어질 수 있으므로 match 구문이 더 효율적이다.

while let 역시 비슷한 개념으로, 이터레이터 등에서 일부 값이 특정 패턴과 일치하는 동안 반복문을 수행하는 데 유용하다. 예를 들어, Option 타입에 대해 Some(...)이면 계속 반복하면서 내부 값을 꺼내고, None이 되면 반복을 종료할 수 있다.

```rust
fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5].into_iter();
    while let Some(num) = numbers.next() {
        println!("현재 숫자: {}", num);
    }
    println!("더 이상 숫자가 없다.");
}
```

분기문 안에서 구조체나 튜플 구조를 분해하는 패턴 매칭 또한 매우 강력하다. 구조체의 필드를 match나 if let 안에서 직접 뽑아낼 수 있어, 본문 로직에서 추가 변수를 만들 필요가 없어진다. 이런 방식은 특히 복합적인 구조체를 다룰 때 코드의 안전성과 가독성을 동시에 높여 준다.

```rust
struct Point {
    x: i32,
    y: i32,
}

fn print_point(p: Point) {
    match p {
        Point { x, y: 0 } => {
            println!("x 축 위의 점 (x: {})", x);
        }
        Point { x: 0, y } => {
            println!("y 축 위의 점 (y: {})", y);
        }
        Point { x, y } => {
            println!("기타 위치의 점 (x: {}, y: {})", x, y);
        }
    }
}

fn main() {
    let p1 = Point { x: 5, y: 0 };
    let p2 = Point { x: 0, y: 3 };
    let p3 = Point { x: 2, y: 4 };

    print_point(p1);
    print_point(p2);
    print_point(p3);
}
```

위처럼 match를 쓰면 구조체 필드를 분해해 미리 변수로 추출할 수 있고, 특정 필드만 조건으로 삼아 분기하는 것도 가능하다. 필드를 일부만 필요로 할 때 언더스코어(\_)를 사용해 무시할 수도 있다.

분기문에서의 패턴 매칭은 단순히 분기 로직을 작성하는 것을 넘어, Rust의 안전성과 표현력을 최대한 활용하는 핵심 기능이다. 컴파일러가 매칭이 누락된 패턴을 경고 또는 에러로 알려주므로, 개발자는 실수를 줄이고 코드 명시성을 극대화할 수 있다. 또한 다양한 유형의 복합 자료구조를 다루면서도 패턴 매칭을 통해 로직과 데이터 구조가 자연스럽게 연결되므로, 코드 유지보수에도 큰 도움을 준다.

이처럼 구조체, 열거형, 튜플 등 복합 데이터 유형을 깔끔하고 안전하게 분기 처리하기 위해서는 match, if let, while let 등 다양한 패턴 매칭 기법을 적절히 조합해야 한다. 특히 복합 자료구조 내부 필드를 직접 구조 분해하는 능력과, 모든 경우의 수를 깔끔히 처리하도록 유도하는 Rust의 컴파일러 체크가 만나면, 자칫 복잡해 보이는 로직도 분기 단계에서 체계적으로 관리할 수 있다. 분기에서의 패턴 매칭 기법은 Rust가 제공하는 풍부한 표현력 중에서도 핵심이라 할 만하다.
