match 가드와 분기

Rust에서 match 표현식은 분기 처리를 간결하고 안전하게 작성할 수 있도록 돕는다. 패턴 매칭을 통해 값의 형태나 속성에 따라 처리 로직을 구분하는 것은 매우 직관적이며, 컴파일 시점에 많은 오류를 잡을 수 있다. 그런데 단순히 패턴만으로는 다루기 애매한 분기 조건도 있을 수 있다. 예를 들어 특정 범위에 속하는지, 추가적인 논리 비교가 필요한 상황 등을 처리할 때 match 가드를 활용하면 된다.

match 가드는 match 각 분기에서 패턴과 함께 사용하는 추가 조건으로, if 키워드를 통해 표현된다. 실제 코드를 살펴보면 더 명확하다.

fn match_guard_example(x: i32) {
    match x {
        n if n < 0 => println!("음수이다: {}", n),
        n if n == 0 => println!("0이다"),
        n if n > 0 => println!("양수이다: {}", n),
        _ => println!("매치되지 않는 값이다."),
    }
}

match 키워드 뒤에 오는 괄호 안의 값을 먼저 패턴 매칭으로 비교한 뒤, 선택된 분기에서 if 뒤에 정의된 조건문을 확인한다. 위 예제에서는 n이라는 이름으로 바인딩된 값에 대해 n < 0, n == 0, n > 0 같은 조건을 검사한다. 이처럼 패턴이 일치해야 하고 if 조건까지 만족해야 최종적으로 해당 분기가 선택된다.

match 가드를 사용할 때 주의할 점은, 각 분기의 패턴이 일치해야만 가드가 평가된다는 사실이다. 다시 말해, match 가드의 조건이 먼저 평가되는 것이 아니라 패턴 매칭이 끝난 뒤에 가드가 수행된다. 이를 통해 불필요한 조건 평가를 줄이고, 코드 가독성을 높일 수 있다.

match 가드가 없을 때는 범위를 이용한 매칭이나 여러 패턴을 묶는 or 패턴(|)을 활용하는 식으로 처리할 수 있다. 예를 들어 어떤 값을 0에서 10 사이일 때와 11부터 20 사이일 때로 구분하려면 다음과 같은 패턴 매칭으로도 충분하다.

fn range_match(x: u32) {
    match x {
        0..=10 => println!("0 이상 10 이하이다"),
        11..=20 => println!("11 이상 20 이하이다"),
        _ => println!("그 밖의 값이다"),
    }
}

하지만 범위 매칭만으로 해결이 어렵거나, 패턴 매칭 이후에 추가 검증이 필요할 때 match 가드를 활용할 수 있다. 예를 들어 특정 범위 안에 속하더라도, 나머지 연산 결과에 따라 다른 처리를 해야 한다면 가드가 유용하다.

여기서는 먼저 0..=10 범위에 속하는지 확인하고, 그 패턴이 일치하면 if x % 2 == 0을 추가로 평가한다. 범위 매칭과 가드가 함께 쓰이면서 코드가 간결해지고 의도를 명확히 표현할 수 있다.

가끔 match 가드 안에서 메서드 호출처럼 부수 효과(side effect)가 있는 코드를 사용하는 경우가 있는데, 가독성과 유지 보수성 측면에서는 신중하게 접근해야 한다. 가드는 분기 조건을 한층 정교화하기 위한 수단이므로 로직 자체를 복잡하게 만들기보다는, 추가 메서드 호출이나 복잡한 연산은 분기 안에서 처리하는 편이 낫다. 가드는 어디까지나 조건 검사 용도로 간결하게 유지하는 것이 바람직하다.

match 가드와 다른 분기 기법을 함께 써야 할 때가 있다. 예를 들어 일부 분기는 단순 패턴 매칭으로 충분하지만, 일부 분기는 논리 연산자 &&, || 등을 사용해야 할 수도 있다. 그러한 경우에는 각각의 패턴 뒤에 가드를 추가하거나, or 패턴(|)과 가드를 조합하는 식으로 확장 가능하다. 다만, 많은 논리식을 가드에 몰아넣으면 코드가 지나치게 복잡해지므로, 꼭 필요한 범위 내에서만 사용해야 유지 보수가 편하다.

패턴 매칭의 또 다른 특징인 ref, ref mut, @ 바인딩 등과도 가드를 함께 사용할 수 있다. 예를 들어 값의 일부를 매칭으로 추출해낸 후, 그 추출된 값이 특정 조건을 만족할 때만 매칭이 되도록 세밀하게 제어할 수 있다.

여기서는 튜플 (a, b)를 추출한 뒤, a == b인 조건을 확인하거나 a > b인 조건을 추가로 확인한다. 이처럼 match 가드는 패턴 매칭을 정제하는 데 있어 큰 유연성을 제공한다.

정리하자면, match 가드는 기존의 패턴 매칭으로는 다루기 어려운 논리적 분기를 자연스럽게 표현할 수 있도록 해주는 기능이다. Rust가 제공하는 다른 분기 문법인 if, if let, while let 등에 비해 match는 보다 총체적인 분기 처리를 수행하는 데 장점이 많다. 여기에 가드를 더하면 더 복잡하고 미묘한 조건까지도 안전하게 다룰 수 있다. 다만 가드를 너무 많이 사용해서 패턴 매칭 식이 지나치게 복잡해지지 않도록 주의하는 것이 좋다. 코드를 간결하고 읽기 쉽게 유지하면서 필요한 분기만 세밀하게 제어하는 것이 match 가드를 올바르게 사용하는 핵심이다.

Last updated