Rust: с нуля до своего органайзера Урок 32 из 40
Result: сообщить о неудачной операции
Урок 32. Превратить текст в число минут и объяснить неверный ввод без остановки программы.
Текст переведён с помощью ИИ.
Предварительно: уроки 10, 22 и 29–31. Если Some и None смешиваются, повторите урок 31.
Образ и опорная карта
Если карточки в ящике нет, мы получаем отсутствие. Если на карточке вместо минут написано «скоро», карточка есть, но прочитать число не удалось. Result<T, E> — стандартное перечисление Rust для операции, которая может завершиться успешно или с ошибкой. Ok(T) хранит успешный результат типа T, Err(E) — сведения об ошибке типа E. Образ ограничен: компилятор проверяет, что мы обработали варианты, но не сочиняет понятное человеку сообщение об ошибке за нас.
Текст → попытка разбора → Ok(число) или Err(причина) → match → ответ. В Result<u32, String> успех содержит u32, ошибка — принадлежащий программе текст String. Запятая в <u32, String> разделяет два типа. Метод .parse::<u32>() пытается прочитать из текста число u32; запись ::<u32> указывает методу нужный тип результата. Это указание типа после имени метода, а не сравнение и не создание коллекции. Сам метод возвращает Result, поэтому неверный текст не заставляет программу аварийно завершиться.
Две попытки разбора
Сохраните прежний src/main.rs проекта organizer, замените весь файл и выполните cargo run рядом с Cargo.toml. Другие файлы и зависимости не меняются. Предскажите оба сообщения.
Функция read_minutes превращает ошибку разбора в наше объяснение. Err(_) распознаёт неудачу и знакомым из урока 30 знаком _ не сохраняет технические подробности, которые мы пока не показываем читателю. Ветви match возвращают один тип Result<u32, String>. Затем main явно разбирает и успех, и ошибку.
fn read_minutes(text: &str) -> Result<u32, String> {
match text.parse::<u32>() {
Ok(minutes) => Ok(minutes),
Err(_) => Err(String::from("Нужно целое число минут")),
}
}
fn main() {
for text in ["25", "скоро"] {
match read_minutes(text) {
Ok(minutes) => println!("Минут: {minutes}"),
Err(message) => println!("Ошибка: {message}"),
}
}
}
Минут: 25
Ошибка: Нужно целое число минут
Здесь 0 тоже успешно разбирается как u32: синтаксически это число. Правило «минут должно быть больше нуля» — отдельная проверка смысла, её добавим в следующем уроке. Отрицательное число не подходит u32; для него функция вернёт Err.
Ошибка — значение, а не крах
Result<u32, String> нельзя выдать за готовый u32. Следующий отдельный пример отклоняется с E0308:
fn main() {
let minutes: u32 = "25".parse::<u32>();
println!("{minutes}");
}
У Result есть метод .unwrap(), который извлекает значение при Ok, но останавливает программу с panic при Err. Для пользовательского ввода он не подходит: неверное число — ожидаемая ситуация, которую нужно объяснить. В этом уроке обрабатывайте оба варианта через match. Option из урока 31 отвечает «есть ли значение?», а Result дополнительно несёт причину неудачи.
Проверка понимания
- Что означает
Stringво втором местеResult<u32, String>? - Почему
"0".parse::<u32>()само по себе не ошибка? - Почему
.unwrap()опасен для ввода человека?
Проверьте: тип сообщения об ошибке; ноль — корректная запись числа; при Err программа остановится вместо объяснения. Восстановите опорную карту без страницы.
Задание
Обязательное. Напишите read_minutes(text: &str) -> Result<u32, String> как в примере, но с сообщением Введите число минут. Проверьте тексты "30" и "много", выведите Минут: 30 и Ошибка: Введите число минут. Число должно приходить из Ok, а сообщение — из Err.
Граница. Проверьте "0" и объясните, почему разбор успешен, хотя ноль позже может быть отклонён правилом задачи.
Подсказка
Сначала match text.parse::<u32>(), затем в main второй match над результатом функции. Не применяйте .unwrap().
Эталон после попытки
fn read_minutes(text: &str) -> Result<u32, String> {
match text.parse::<u32>() {
Ok(minutes) => Ok(minutes),
Err(_) => Err(String::from("Введите число минут")),
}
}
fn main() {
for text in ["30", "много"] {
match read_minutes(text) {
Ok(minutes) => println!("Минут: {minutes}"),
Err(message) => println!("Ошибка: {message}"),
}
}
}
Минут: 30
Ошибка: Введите число минут
Так программа сообщает о неверном вводе и продолжает работу. Официальный разбор Result.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.