Обработка ошибок Rust — захват нескольких ошибок

Я начал изучать Rust на прошлой неделе, читая книги и статьи и одновременно пытаясь конвертировать код из других языков.

Я столкнулся с ситуацией, которую я пытаюсь проиллюстрировать с помощью приведенного ниже кода (который представляет собой упрощенную версию того, что я пытался преобразовать из другого языка):

#[derive(Debug)]
struct InvalidStringSize;
impl std::fmt::Display for InvalidStringSize {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "string is too short")
    }
}
impl std::error::Error for InvalidStringSize {}

pub fn extract_codes_as_ints(
    message: String,
) -> Result<(i32, i32, i32), Box<dyn std::error::Error>> {
    if message.len() < 20 {
        return Err(Box::new(InvalidStringSize {}));
    }
    let code1: i32 = message[0..3].trim().parse()?;
    let code2: i32 = message[9..14].trim().parse()?;
    let code3: i32 = message[17..20].trim().parse()?;
    Ok((code1, code2, code3))
}

Итак, в основном я хочу извлечь 3 целых числа из определенных позиций заданной строки (я также мог бы попытаться проверить другие символы на наличие некоторых шаблонов, но я пропустил эту часть).

Мне было интересно, есть ли способ «поймать» или проверить все три результата вызовов синтаксического анализа одновременно? Я не хочу добавлять блок соответствия для каждого, я просто хотел бы проверить, не привел ли кто-нибудь к ошибке, и в этом случае вернуть другую ошибку. Имеет смысл?

Единственное решение, которое я мог придумать до сих пор, - это создать другую функцию со всеми анализами и сопоставить ее результат. Есть ли другой способ сделать это?

Кроме того, любые отзывы/предложения по другим частям кода очень приветствуются, я изо всех сил пытаюсь найти «правильный способ» делать что-то в Rust.

Я не совсем понимаю, чего вы хотите: вы уже ошибаетесь, когда число не поддается разбору, не так ли?

Chayim Friedman 10.04.2022 00:34

@ChayimFriedman Насколько я понимаю, OP хочет поймать ошибку синтаксического анализа и в этом случае вернуть ошибку другого типа.

Lagerbaer 10.04.2022 00:44

Да, именно так, как сказал @Lagerbaer, извините, если я не ясно выразился. Другой возможностью было бы добавить некоторый код обработки ошибок, например, ведение журнала или что-то еще.

felipou 10.04.2022 01:11
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
1
3
39
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Идиоматический способ добиться этого — определить свой собственный тип ошибки и вернуть его с From<T> реализацией для каждого типа ошибки T, который может возникнуть в вашей функции. Оператор ? выполнит .into() преобразования, чтобы соответствовать типу ошибки, который объявлена ​​вашей функцией.

Коробочная ошибка здесь излишня; просто объявите перечисление со списком всех способов, которыми функция может дать сбой. Вариант для целочисленной ошибки синтаксического анализа может даже зафиксировать пойманную ошибку.

use std::fmt::{Display, Formatter, Error as FmtError};
use std::error::Error;
use std::num::ParseIntError;

#[derive(Debug, Clone)]
pub enum ExtractCodeError {
    InvalidStringSize,
    InvalidInteger(ParseIntError),
}

impl From<ParseIntError> for ExtractCodeError {
    fn from(e: ParseIntError) -> Self {
        Self::InvalidInteger(e)
    }
}

impl Error for ExtractCodeError {}

impl Display for ExtractCodeError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        match self {
            Self::InvalidStringSize => write!(f, "string is too short"),
            Self::InvalidInteger(e) => write!(f, "invalid integer: {}", e)
        }
    }
}

Теперь нам просто нужно изменить тип возвращаемого значения вашей функции и заставить его возвращать ExtractCodeError::InvalidStringSize, когда длина слишком мала. Больше ничего менять не нужно, так как ParseIntError автоматически преобразуется в ExtractCodeError:

pub fn extract_codes_as_ints(
    message: String,
) -> Result<(i32, i32, i32), ExtractCodeError> {
    if message.len() < 20 {
        return Err(ExtractCodeError::InvalidStringSize);
    }
    let code1: i32 = message[0..3].trim().parse()?;
    let code2: i32 = message[9..14].trim().parse()?;
    let code3: i32 = message[17..20].trim().parse()?;
    Ok((code1, code2, code3))
}

В качестве дополнительного бонуса вызывающие функции смогут легче проверять ошибки, чем с помощью dyn Error в рамке.

В более сложных случаях, например, когда вы хотите немного изменить ошибку для каждого возможного появления ParseIntError, вы можете использовать .map_err() в результатах для преобразования ошибки. Например:

something_that_can_fail.map_err(|e| SomeOtherError::Foo(e))?;

Другие вопросы по теме

Почему я получаю сообщение об ошибке «java.lang.ArrayIndexOutOfBoundsException: индекс 5 выходит за границы для длины 5» для моего метода findPosition?
[Предупреждение Vue]: ошибка рендеринга: ошибка «TypeError: невозможно прочитать свойства неопределенного (чтение« длины »)» при использовании таблиц данных в vue
Как в zsh сделать цикл, который, когда команда НЕ ПРОДАЕТСЯ, повторяет ту же команду с новыми аргументами до тех пор, пока не сработает ошибка
Как обрабатывать повторный запуск функции Azure при использовании привязки очереди сообщений?
Значение типа "Объект?" не может быть присвоено переменной типа «SigninCharacter»
Как я могу увидеть, какой элемент списка генерирует предупреждение/сообщение об ошибке в R?
Как отключить автоматическую регистрацию Elmah?
Объект aiosqlite «Результат» не имеет атрибута «выполнить»
В любом случае: вернуть вложенные/обернутые ошибки
Альтернатива MUI для уведомления AntD