패턴 매칭은 Rust에서 값을 구조에 따라 분해하고 match, if let, while let 구문을 사용하여 복잡한 타입을 분석하고 처리할 수 있게 해줍니다. 구조 해체는 튜플, 구조체, 열거형(enum) 및 심지어 참조를 다루는 데 유용합니다.
열거형 예:
enum Message { Quit, ChangeColor(i32, i32, i32), Write(String), } let m = Message::ChangeColor(255, 0, 0); match m { Message::Quit => println!("Quit!"), Message::ChangeColor(r, g, b) => println!("Color: {} {} {}", r, g, b), Message::Write(text) => println!("Text: {}", text), }
구조 해체 예:
struct Point { x: i32, y: i32 } let p = Point { x: 10, y: 20 }; let Point { x, y } = p;
주의할 점:
ref와 ref mut를 사용하면 해체할 때 참조를 얻을 수 있습니다.@를 사용하여 패턴의 일부를 "이름 바꾸기" 할 수 있습니다.if guard)에 의한 매칭이 가능합니다.&SomeType) 시 소유권과 대여(borrowing)에 대해 기억해야 합니다.패턴의 일부를 무시하고 컴파일러 경고를 피하기 위해 항상 "_" (언더스코어)를 사용할 수 있나요?
항상 그렇지는 않습니다. 언더스코어는 실제로 값을 건너뛰지만, enum의 모든 변형을 처리하지 않고 "_"로 catch-all을 사용할 경우 나중에 enum이 확장될 때 새로운 변형을 처리하지 못할 수 있습니다. 항상 중요한 변형을 명시적으로 나열하여 컴파일러가 처리가 안 된 경우를 경고하도록 하는 것이 좋습니다!
match result { Ok(val) => ..., Err(err) => ..., //_ => ... // enum에 대해서는 권장되지 않음! }
이야기
IoT 애플리케이션에서 새로운 열거형 변형을 추가할 때 패턴 매칭에서 catch-all "_"가 사용되어 장치가 응답하지 않게 되었습니다. 이 오류는 배포 시까지 보이지 않았습니다. 이후 중요한 enum은 항상 변형을 명시적으로 나열하여 처리되었습니다.
이야기
중첩된 튜플을 가진 복잡한 구조체에서 재귀 필드의 구조 해체 문법을 추가하는 것을 잊어, 코드가 우연히 큰 객체를 복제하게 되어 성능 저하가 발생했습니다.
이야기
스레드 간 메시지를 전달하는 기능에서 if-let을 통해 구조 해체를 사용했지만 드문 열거형 변형을 무시했습니다. 새로운 비즈니스 로직이 나타날 때 메시지가 단순히 사라졌습니다. 이후 팀 스타일에서 각 match 표현식은 catch-all 없이 포괄적이어야 한다는 규칙이 세워졌습니다.