% Конструкция if let

Иногда хочется сделать определённые вещи менее неуклюже. Например, скомбинировать if и let чтобы более удобно сделать сопоставление с образцом. Для этого есть if let.

В качестве примера рассмотрим Option<T>. Если это Some<T>, мы хотим вызвать функцию на этом значении, а если это None — не делать ничего. Вроде такого:


# #![allow(unused_variables)]
#fn main() {
# let option = Some(5);
# fn foo(x: i32) { }
match option {
    Some(x) => { foo(x) },
    None => {},
}
#}

Здесь необязательно использовать match. if тоже подойдёт:


# #![allow(unused_variables)]
#fn main() {
# let option = Some(5);
# fn foo(x: i32) { }
if option.is_some() {
    let x = option.unwrap();
    foo(x);
}
#}

Но оба этих варианта выглядят странно. Мы можем исправить это с помощью if let:


# #![allow(unused_variables)]
#fn main() {
# let option = Some(5);
# fn foo(x: i32) { }
if let Some(x) = option {
    foo(x);
}
#}

Если сопоставление с образцом успешно, имена в образце связываются с соответствующими частями разбираемого значения, и блок исполняется. Если значение не соответствует образцу, ничего не происходит.

Если вы хотите делать что-то ещё при несовпадении с образцом, используйте else:


# #![allow(unused_variables)]
#fn main() {
# let option = Some(5);
# fn foo(x: i32) { }
# fn bar() { }
if let Some(x) = option {
    foo(x);
} else {
    bar();
}
#}

while let

Похожим образом, while let можно использовать для перебора значений, пока они соответствуют образцу. Код вроде такого:


# #![allow(unused_variables)]
#fn main() {
# let option: Option<i32> = None;
loop {
    match option {
        Some(x) => println!("{}", x),
        _ => break,
    }
}
#}

Превращается в такой:


# #![allow(unused_variables)]
#fn main() {
# let option: Option<i32> = None;
while let Some(x) = option {
    println!("{}", x);
}
#}