Потік контролю Let

Rust має кілька конструкцій потоку керування, які відрізняються від інших мов. Вони використовуються для зіставлення шаблонів:

  • вирази if let
  • вирази let else
  • вирази while let

вирази if let

Вираз if let дозволяє виконувати інший код залежно від того, чи відповідає значення шаблону :

use std::time::Duration;

fn sleep_for(secs: f32) {
    if let Ok(dur) = Duration::try_from_secs_f32(secs) {
        std::thread::sleep(dur);
        println!("проспав {:?}", dur);
    }
}

fn main() {
    sleep_for(-10.0);
    sleep_for(0.8);
}

вирази let else

Для загального випадку зіставлення шаблону і повернення з функції використовуйте let else. Випадок "else" повинен відрізнятися (return, break або паніка - що завгодно, але не випадання з кінця блоку).

fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
    let s = if let Some(s) = maybe_string {
        s
    } else {
        return Err(String::from("отримав None"));
    };

    let first_byte_char = if let Some(first_byte_char) = s.chars().next() {
        first_byte_char
    } else {
        return Err(String::from("отримав порожній рядок"));
    };

    if let Some(digit) = first_byte_char.to_digit(16) {
        Ok(digit)
    } else {
        Err(String::from("не шістнадцяткова цифра"))
    }
}

fn main() {
    println!("результат: {:?}", hex_or_die_trying(Some(String::from("foo"))));
}

Подібно до if let, існує варіант while let, який багаторазово перевіряє значення на відповідність шаблону:

fn main() {
    let mut name = String::from("Comprehensive Rust 🦀");
    while let Some(c) = name.pop() {
        println!("character: {c}");
    }
    // (There are more efficient ways to reverse a string!)
}

Тут String::pop повертає Some(c) поки рядок не стане порожнім, після чого поверне None. Використання while let дозволяє нам продовжувати ітерацію по всіх елементах.

This slide should take about 10 minutes.

if-let

  • На відміну від match, if let не має охоплювати всі гілки. Це може зробити його більш лаконічним, ніж match.
  • Загальним використанням є обробка значень Some під час роботи з Option.
  • На відміну від match, if let не підтримує захисні вирази для збігу шаблонів.

let-else

if-let може накопичуватись, як показано. Конструкція let-else підтримує згладжування цього вкладеного коду. Перепишіть незручну версію для студентів, щоб вони могли побачити перетворення.

Переписана версія така:

#![allow(unused)]
fn main() {
fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
    let Some(s) = maybe_string else {
        return Err(String::from("отримав None"));
    };

    let Some(first_byte_char) = s.chars().next() else {
        return Err(String::from("отримав порожній рядок"));
    };

    let Some(digit) = first_byte_char.to_digit(16) else {
        return Err(String::from("не шістнадцяткова цифра"));
    };

    return Ok(digit);
}
}

while-let

  • Зверніть увагу, що цикл while let триватиме, доки значення відповідає шаблону.
  • Ви можете переписати цикл while let як нескінченний цикл з оператором if, який переривається, коли для name.pop() немає значення для розгортання. Цикл while let забезпечує синтаксичний цукор для наведеного вище сценарію.