Оператор вопросительного знака '?'
Часть раздела Логика и управление потоком путешествия по Rust на Coddy. Урок 46 из 66.
При работе с функциями, возвращающими Result, часто требуется обрабатывать ошибки: либо обрабатывать их локально, либо передавать их вызывающей функции. Rust предоставляет элегантный оператор для этого распространённого шаблона: оператор вопросительного знака ?.
Оператор ? предоставляет удобный способ распространять ошибки без написания громоздких операторов match. Когда вы помещаете ? после Result, он автоматически распаковывает значение Ok или немедленно возвращает управление из текущей function с помощью 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, оператор ? немедленно возвращает эту ошибку из всей function.
Обратите внимание на синтаксис ::<i32>. Он называется turbofish и сообщает Rust, в какой тип следует преобразовать строку при разборе. Функция возвращает Result<i32, std::num::ParseIntError>, где i32 — тип успешного результата, а std::num::ParseIntError — тип ошибки, возвращаемый, когда parsing fails.
Оператор ? можно использовать только в функциях, которые возвращают 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
Попробуйте сами
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)
// Print "Parsing error" for Err(_)
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
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Итоги: поиск элементаПотренируйтесь самостоятельно: Онлайн-компилятор Rust