Потік контролю 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> { if let Some(s) = maybe_string { if let Some(first_byte_char) = s.chars().next() { if let Some(digit) = first_byte_char.to_digit(16) { Ok(digit) } else { return Err(String::from("не шістнадцяткова цифра")); } } else { return Err(String::from("отримав порожній рядок")); } } else { return Err(String::from("отримав None")); } } 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
дозволяє нам продовжувати ітерацію по всіх елементах.
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
забезпечує синтаксичний цукор для наведеного вище сценарію.