Потік контролю Let
Rust має кілька конструкцій потоку керування, які відрізняються від інших мов. Вони використовуються для зіставлення шаблонів:
- вирази
if let - вирази
let else - вирази
while let
вирази if let
Вираз if let дозволяє виконувати інший код залежно від того, чи відповідає значення шаблону :
use std::time::Duration;
fn sleep_for(secs: f32) {
if let Ok(duration) = Duration::try_from_secs_f32(secs) {
std::thread::sleep(duration);
println!("проспав {duration:?}");
}
}
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забезпечує синтаксичний цукор для наведеного вище сценарію.