if let и while let в Rust
Ты уже обрабатывал Option и Result через match. Но чаще всего на деле тебе важен только один образец, а всё остальное можно пропустить. Полный match с веткой _ => {}, которая ничего не делает, работает, но это больше церемоний, чем нужно. if let — короткий путь.
Чем здесь неудобен полный match
Заголовок раздела «Чем здесь неудобен полный match»fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("Возраст: {value}"), _ => {}, // этот случай нам на самом деле не важен }}_ => {} ничего не делает — он нужен только для того, чтобы выполнить правило match «каждый случай должен быть обработан». Если ты хочешь что-то сделать только для Some, такого кода слишком много для такой простой мысли.
fn main() { let age: Option<i32> = Some(30);
if let Some(value) = age { println!("Возраст: {value}"); }}Вывод:
Возраст: 30Читай это так: «если age подходит под образец Some(value), выполни этот блок, а в value положи то, что было внутри». Если age равно None, блок просто пропускается — без ошибки и без вывода.
Добавляем else
Заголовок раздела «Добавляем else»У if let может быть else, как у обычного if:
fn main() { let age: Option<i32> = None;
if let Some(value) = age { println!("Возраст: {value}"); } else { println!("Возраст не указан"); }}if let с Result
Заголовок раздела «if let с Result»С Result, с которым ты познакомился в уроке Result, всё работает точно так же:
fn main() { let input = "42";
if let Ok(number) = input.parse::<i32>() { println!("Получилось число: {number}"); } else { println!("Не удалось разобрать"); }}Цепочки с else if let
Заголовок раздела «Цепочки с else if let»Как у if есть else if, так и за if let может идти else if let. Rust пробует образцы по очереди и выполняет первый подходящий блок. Это удобно, когда значение можно найти в нескольких местах и они идут в порядке предпочтения:
fn main() { let nickname: Option<&str> = None; let full_name: Option<&str> = Some("Феррис Краб");
if let Some(nick) = nickname { println!("Привет, {nick}!"); } else if let Some(name) = full_name { println!("Здравствуйте, {name}."); } else { println!("Здравствуй, незнакомец."); }}Вывод:
Здравствуйте, Феррис Краб.nickname равно None, поэтому первый блок пропускается. full_name подходит под Some(name), поэтому выполняется второй блок, а до последнего else дело не доходит. В любое место цепочки можно добавить и обычное условие, например else if is_admin { ... }.
Каждая переменная существует только внутри своего блока: nick нельзя использовать во втором блоке, а name — после окончания цепочки. Если распакованное значение нужно в остальном коде, посмотри на let-else в уроке Сопоставление с образцом.
while let
Заголовок раздела «while let»while let применяет ту же идею к циклу: цикл продолжается, пока значение подходит под образец. Особенно удобно так опустошать коллекцию:
fn main() { let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() { println!("{top}"); }}Вывод:
321.pop() возвращает Some(value), пока в векторе что-то есть, и None, когда он опустел, — в этот момент while let сам останавливает цикл. Проверять длину вручную не нужно.
if let или match — что выбрать
Заголовок раздела «if let или match — что выбрать»Используй match, когда действительно нужно по-разному обработать несколько случаев. Бери if let, когда тебе важен ровно один образец, а всё остальное можно просто пропустить. Это не замена match, а лишь более короткая запись частого случая «мне нужна только одна ветка».
Практика
Заголовок раздела «Практика»1. Сумма из стека
Заголовок раздела «1. Сумма из стека»Начни с let mut numbers = vec![4, 8, 15]; и счётчика total, равного 0. С помощью while let и .pop() снимай числа с конца по одному, прибавляй каждое к total и выводи число и новую сумму. Подсказка: total нужен mut, а total += n прибавляет к нему число.
Показать решение
fn main() { let mut numbers = vec![4, 8, 15]; let mut total = 0;
while let Some(n) = numbers.pop() { total += n; println!("взяли {n}, сумма теперь {total}"); }}Вывод:
взяли 15, сумма теперь 15взяли 8, сумма теперь 23взяли 4, сумма теперь 27.pop() берёт элементы с конца, поэтому первым выходит 15.
2. Проверяем возраст из текста
Заголовок раздела «2. Проверяем возраст из текста»Сохрани let input = "17";. Если строка разбирается как u32, выведи, взрослый это человек (18 или больше) или несовершеннолетний. Если не разбирается — выведи, что это не число. Попробуй заменить input на "abc". Подсказка: положи обычный if / else внутрь блока if let.
Показать решение
fn main() { let input = "17";
if let Ok(age) = input.parse::<u32>() { if age >= 18 { println!("{age} — взрослый"); } else { println!("{age} — несовершеннолетний"); } } else { println!("'{input}' — это не число"); }}Вывод:
17 — несовершеннолетнийС input = "abc" разбор не удаётся, выполняется внешний else, и программа выводит 'abc' — это не число.
if let Образец = значение { ... }выполняет блок, только еслизначениеподходит подОбразец, — всё остальное молча пропускается.- Добавь
else, чтобы обработать неподходящий случай, как у обычногоif, а несколько образцов связывай черезelse if let. while let Образец = значение { ... }крутит цикл, пока значение подходит, — удобно, чтобы опустошить коллекцию через.pop().if let/while let— когда важен один образец;match— когда нужно по-разному обработать несколько случаев.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Что произойдёт, если выполнить if let Some(value) = age, когда age равно None?
2. Когда стоит выбрать match вместо if let?
3. Когда остановится цикл while let Some(top) = stack.pop() { ... }?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- Лаконичный поток управления с if let — книга «Язык программирования Rust»: официальное введение в
if let(перевод на русский). Про let-else рассказано в английской версии главы (на английском). - if let — Rust на примерах: запускаемые примеры с
Optionи собственными перечислениями, а ещё объяснение, почему для одного образцаif letлучшеmatch(перевод на русский). - while let — Rust на примерах: цикл, переписанный из
loop+matchв более короткийwhile let(перевод на русский). if letpatterns — The Rust Reference (на английском): точные правила, в том числе какif letсвязан сmatch.