if let
어떤 경우에는 열거형을 매칭할 때 match가 어색할 수 있습니다. 예를 들어:
#![allow(unused)]
fn main() {
// `Option<i32>` 타입의 `optional` 생성
let optional = Some(7);
match optional {
Some(i) => println!("이것은 정말 긴 문자열이며 `{:?}`입니다", i),
_ => {},
// ^ `match`는 철저해야(exhaustive) 하기 때문에 필요합니다. 공간 낭비처럼
// 보이진 않나요?
};
}
이런 경우 if let이 더 깔끔하며, 추가로 다양한 실패 옵션을 지정할 수 있습니다:
fn main() {
// 모두 `Option<i32>` 타입입니다
let number = Some(7);
let letter: Option<i32> = None;
let emoticon: Option<i32> = None;
// `if let` 구문은 다음과 같이 읽힙니다: "만약 `let`이 `number`를
// `Some(i)`로 구조 분해한다면, 블록(`{}`)을 실행하라."
if let Some(i) = number {
println!("{:?}가 매칭되었습니다!", i);
}
// 실패한 경우를 지정해야 한다면, else를 사용하세요:
if let Some(i) = letter {
println!("{:?}가 매칭되었습니다!", i);
} else {
// 구조 분해에 실패했습니다. 실패 사례로 전환합니다.
println!("숫자와 매칭되지 않았습니다. 문자로 해봅시다!");
}
// 변경된 실패 조건을 제공합니다.
let i_like_letters = false;
if let Some(i) = emoticon {
println!("{:?}가 매칭되었습니다!", i);
// 구조 분해에 실패했습니다. 다른 실패 분기를 타야 하는지
// `else if` 조건을 평가합니다:
} else if i_like_letters {
println!("숫자와 매칭되지 않았습니다. 문자로 해봅시다!");
} else {
// 조건이 거짓(false)으로 평가되었습니다. 이 분기가 기본입니다:
println!("문자는 별로예요. 이모티콘 :)으로 가봅시다!");
}
}
같은 방식으로, if let은 모든 열거형 값을 매칭하는 데 사용될 수 있습니다:
// 예제 열거형
enum Foo {
Bar,
Baz,
Qux(u32)
}
fn main() {
// 예제 변수 생성
let a = Foo::Bar;
let b = Foo::Baz;
let c = Foo::Qux(100);
// 변수 a는 Foo::Bar와 매칭됩니다
if let Foo::Bar = a {
println!("a는 foobar입니다");
}
// 변수 b는 Foo::Bar와 매칭되지 않습니다
// 따라서 아무것도 출력되지 않습니다
if let Foo::Bar = b {
println!("b는 foobar입니다");
}
// 변수 c는 값을 가진 Foo::Qux와 매칭됩니다
// 앞선 예제의 Some()과 유사합니다
if let Foo::Qux(value) = c {
println!("c는 {}입니다", value);
}
// 바인딩은 `if let`에서도 작동합니다
if let Foo::Qux(value @ 100) = c {
println!("c는 100입니다");
}
}
또 다른 장점은 if let을 사용하면 파라미터가 없는 열거형 변체도 매칭할 수 있다는 점입니다. 이는 열거형이 PartialEq를 구현하거나 유도하지 않는 경우에도 마찬가지입니다. 이러한 경우 if Foo::Bar == a는 열거형 인스턴스를 비교할 수 없기 때문에 컴파일에 실패하지만, if let은 계속 작동합니다.
도전해 보시겠습니까? 다음 예제를 if let을 사용하도록 수정해 보세요:
// 이 열거형은 의도적으로 PartialEq를 구현하거나 유도(derive)하지 않았습니다.
// 그래서 아래에서 Foo::Bar == a 를 비교하는 것이 실패합니다.
enum Foo {Bar}
fn main() {
let a = Foo::Bar;
// 변수 a는 Foo::Bar와 매칭됩니다
if Foo::Bar == a {
// ^-- 이것은 컴파일 타임 에러를 발생시킵니다. 대신 `if let`을 사용하세요.
println!("a는 foobar입니다");
}
}