질문의 역사
Rust의 match 연산자는 함수형 언어에서 차용한 강력한 패턴 매칭 도구입니다. C/C++의 유사한 도구들과는 달리, Rust는 엄격한 완전성 검사(exhaustiveness checking)를 실시하며, 각 가능한 경우에 대해 분기 옵션이 필요합니다.
문제점
match와 관련된 오류는 대개 (예: enum) 타입의 모든 경우를 잘못 고려하거나, guard(분기에 대한 조건)를 잘못 처리하거나, 복잡한 중첩 구조와 관련이 있습니다. 잘못된 처리는 컴파일 단계에서 오류를 발생시키거나, 암묵적으로 잘못된 논리로 이어질 수 있습니다.
해결책
_).if)을 더합니다.코드 예시:
enum Shape { Circle(f64), Rectangle { width: f64, height: f64 }, } fn print_area(s: Shape) { match s { Shape::Circle(r) if r > 0.0 => println!("area = {}", 3.14 * r * r), Shape::Rectangle { width, height } if width > 0.0 && height > 0.0 => println!("area = {}", width * height), _ => println!("invalid shape"), } }
주요 특징:
match에서 분기의 순서가 실행에 영향을 미치나요?
네, 분기의 순서가 중요합니다: 첫 번째 일치 항목이 발견되면 이후의 분기는 검사되지 않습니다. 이는 패턴 가드와 함께 특히 중요합니다. 이전에 guard가 있는 분기가 있으면 catch-all 이전에 값을 가로챌 수 있습니다.
enum에 대해 match 시 catch-all (_)이 필수인가요?
아니요, 모든 경우를 명시적으로 처리했다면 필요하지 않습니다 (그리고 타입의 선언이 시간이 지남에 따라 변경되지 않는다면). 그러나 추가 값이 나타날 수 있는 타입을 다룰 때나 모든 분기를 명시적으로 처리하고 싶지 않을 때는 catch-all이 필요합니다.
하나의 match 분기에서 여러 패턴(alternatives)을 사용할 수 있나요?
네, 수직선(|)을 통해 패턴을 결합할 수 있습니다:
match x { 1 | 2 | 3 => println!("one, two or three"), _ => println!("something else"), }
_을 너무 일찍 사용하기개발자가 catch-all을 처음에 작성한 match를 작성했지만, 특정 경우를 올바르게 처리하지 못했습니다.
장점:
프로그램이 컴파일됩니다.
단점:
특정 로직이 결코 작동하지 않으며, 코드의 일부가 다루어지지 않습니다.
enum의 모든 경우를 명시적으로 처리하며, catch-all은 마지막 분기로 두고 다양한 경우에 대한 개별 가드를 둡니다.
장점:
예측 가능성이 있으며, 컴파일러가 경우를 잊지 않도록 도와주며, 타입을 쉽게 확장할 수 있습니다.
단점:
많은 경우가 있을 경우 추가 템플릿 코드가 필요합니다.