Оператор вопросительного знака '?'
Часть раздела Logic & Flow путешествия по Rust на Coddy — урок 46 из 66.
При работе с функциями, которые возвращают Result, вам часто нужно обрабатывать ошибки, либо разбираясь с ними локально, либо передавая их выше в вызывающую функцию. Rust предоставляет элегантный оператор для этого распространенного паттерна: оператор вопросительного знака ?.
Оператор ? предоставляет чистый способ распространения ошибок без написания многословных выражений match. Когда вы ставите ? после Result, он автоматически извлекает значение Ok или немедленно возвращает Err из текущей функции:
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // Если парсинг не удался, вернуть ошибку
Ok(number * 2) // Если успешно, удвоить число
}Это эквивалентно написанию полного оператора match, но гораздо более лаконично. Если s.parse::<i32>() возвращает Ok, оператор ? извлекает значение и присваивает его number. Если он возвращает Err, оператор ? немедленно возвращает эту ошибку из всей функции.
Оператор ? может использоваться только в функциях, которые возвращают Result (или Option), так как он должен иметь возможность возвращать ошибку.
Задание
ЛегкоВы получите два входных значения. Первое значение — это строка, которую необходимо преобразовать в целое число, и второе значение — это еще одна строка, которую также необходимо преобразовать в целое число. Создайте функцию с именем add_numbers, которая принимает два строковых среза в качестве параметров и возвращает Result<i32, std::num::ParseIntError>. Внутри функции используйте оператор ? для парсинга обеих строк и верните их сумму, обернутую в Ok. Вызовите функцию с двумя входными значениями и обработайте результат с помощью match.
Требования:
- Прочитайте первый ввод (первое число как строку) и удалите лишние пробелы
- Прочитайте второй ввод (второе число как строку) и удалите лишние пробелы
- Создайте функцию
add_numbers, которая принимает два параметра типа&strи возвращаетResult<i32, std::num::ParseIntError> - Внутри функции преобразуйте первую строку в
i32, используя оператор? - Преобразуйте вторую строку в
i32, используя оператор? - Верните
Ok(sum), где sum — это сумма обоих преобразованных чисел - Вызовите функцию с двумя входными строками
- Используйте выражение
matchдля обработкиResult - В ветке
Ok(value)выведите:Sum: [value] - В ветке
Err(_)выведите:Parsing error
Ввод:
- Первая строка: Строка, представляющая число (например,
15) - Вторая строка: Строка, представляющая другое число (например,
27)
Вывод:
- Если обе строки являются допустимыми числами:
Sum: [result] - Если любую из строк невозможно преобразовать:
Parsing error
Шпаргалка
Оператор вопросительного знака ? предоставляет краткий способ распространения ошибок в функциях, которые возвращают Result.
При размещении после Result оператор ?:
- Распаковывает значение
Okи продолжает выполнение - Немедленно возвращает
Errиз текущей функции, если возникла ошибка
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // Если парсинг не удался, вернуть ошибку
Ok(number * 2) // Если успешно, удвоить число
}Оператор ? может использоваться только в функциях, которые возвращают тип Result или Option.
Попробуйте сами
use std::io;
// TODO: Создайте здесь функцию add_numbers
// Она должна принимать два параметра &str и возвращать Result<i32, std::num::ParseIntError>
fn main() {
// Чтение первого ввода
let mut input1 = String::new();
io::stdin().read_line(&mut input1).expect("Failed to read line");
let input1 = input1.trim();
// Чтение второго ввода
let mut input2 = String::new();
io::stdin().read_line(&mut input2).expect("Failed to read line");
let input2 = input2.trim();
// TODO: Вызовите add_numbers с input1 и input2
// TODO: Используйте match для обработки Result
// Выведите "Sum: [value]" для Ok(value)
// Выведите "Parsing error" для Err(_)
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Logic & Flow
1Продвинутое управление потоком выполнения
Выражение 'match'Сопоставление нескольких значенийСопоставление диапазоновВыражение 'if let'Циклы как выраженияИтоги — Простой парсер команд4Группировка данных с помощью структур
Что такое структура?Обзор структурДоступ к полям структурыИзменяемые структурыСтруктуры как параметры функцийКортежные структурыИтоги: создание структуры Book7Обработка ошибок с помощью 'Result'
Что такое 'Result'?Использование 'match' с 'Result'is_ok() и is_err()Сокращения: unwrap и expectОператор вопросительного знака '?'Парсинг строк в числаИтоги: функция безопасного деления10Замыкания и анонимные функции
Что такое замыкание?Определение простого замыканияЗамыкания с параметрамиЗахват окруженияИтоги: Простое замыкание-сумматор2Введение в векторы
Что такое вектор?Создание вектораДобавление элементов с помощью pushДоступ к элементам вектораИтерация по векторуИзменяемая итерацияУдаление элементовИтоги — Простой счетчик очков5Пары «ключ-значение» в Hash Map
Что такое Hash Map?Создание Hash MapВставка пар «ключ-значение»Доступ к значениямИтерация по Hash MapОбновление значенияУдаление парыИтоги — Счетчик слов8Проект: Простой инвентарь товаров
Настройка проектаДобавление товараПроверка наличияПродажа товараСобираем всё воедино3Список дел в командной строке
Настройка проектаДобавление задачиПросмотр всех задачУдаление задачиИтоговый код6Обработка отсутствия значения с 'Option'
Что такое 'Option'?Использование 'match' с 'Option'is_some() и is_none()Распаковка 'Option'Метод expectЗначение по умолчанию: unwrap_orИтоги: поиск элемента