Есть ли способ сделать unwrap_or_return Error (любую ошибку)

Есть ли способ упростить возврат в следующем примере (первоначально скопированном из здесь):

use std::num::ParseIntError;

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    let first_number = match first_number_str.parse::<i32>() {
        Ok(first_number)  => first_number,
        Err(e) => return Err(e),
    };

    let second_number = match second_number_str.parse::<i32>() {
        Ok(second_number)  => second_number,
        Err(e) => return Err(AnotherError::ParseError("error")),
    };

    Ok(first_number * second_number)
}

Я имею в виду что-то вроде:

use std::num::ParseIntError;

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    let first_number = first_number_str.parse::<i32>()
        .unwrap_or_return(|e| Err(e));

    let second_number = second_number_str.parse::<i32>()
        .unwrap_or_return(|e| Err(AnotherError::ParseError("error"));

    Ok(first_number * second_number)
}

person Omid    schedule 31.01.2020    source источник
comment
Это похоже на: err" title="как вы разворачиваете результат в случае ok или возвращаетесь из функции в случае ошибки"> stackoverflow.com/questions/51344951/ Но не совсем так.   -  person Omid    schedule 31.01.2020
comment
Что такое AnotherError::ParseError? Тип возвращаемого значения предполагает, что он имеет тип ParseIntError.   -  person SCappella    schedule 31.01.2020
comment
Вы правы, это больше похоже на псевдокод. Я имел в виду, что возврат может быть другой ошибкой или даже хорошо (что-то).   -  person Omid    schedule 31.01.2020


Ответы (1)


Вы ищете оператор вопросительного знака, возможно, в сочетании с Result::or или Result::or_else, в зависимости от особенности вашего варианта использования.

Этот пример кода можно переписать как

use std::num::ParseIntError;

pub fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    let first_number = first_number_str.parse::<i32>()?;
    let second_number = second_number_str.parse::<i32>().or_else(|e| Err(e))?;
    // The closure in `or_else` could also return `Ok` or some different error with type `ParseIntError`.
    // let second_number = second_number_str.parse::<i32>().or_else(|_e| Ok(27))?;

    Ok(first_number * second_number)
}

(игровая площадка)

Если вы знаете, что собираетесь вернуть Ok в or_else, Result::unwrap_or более подходит. Ознакомьтесь с другими подобными методами на Result, чтобы узнать, что предлагается.

person SCappella    schedule 31.01.2020
comment
Если вы возвращаете Err из or_else, то может быть чище просто использовать вместо него map_err. - person Frxstrem; 01.02.2020
comment
unwrap_or не возвращается из функции. unwrap_or_return Одной из целей является ОК, так как ранний возврат в случае неудачи. - person Omid; 01.02.2020
comment
Например, если first_number или second_number недействительны, просто верните Ok(0) как можно раньше! - person Omid; 01.02.2020
comment
@Omid Ключевым моментом является оператор ?, который действительно возвращает значение из функции. - person SCappella; 01.02.2020
comment
@SCappella не совсем. Проверьте это: play.rust-lang.org/ - person Omid; 01.02.2020
comment
@Omid А, так ты хочешь, чтобы в этом случае он возвращал Ok? Это не было ясно из вашего вопроса. Оператор вопросительного знака возвращает результат, если он применяется к Err, а не к Ok. Поведение, которое вы хотите, вероятно, менее идиоматично, поэтому я не уверен, что есть простой способ сделать это. Я буду экспериментировать с некоторыми вещами, но никаких гарантий. - person SCappella; 01.02.2020
comment
Вы правы, я изменю вопрос и одобрю ваш ответ. Затем задам другой вопрос непосредственно для досрочного возвращения. - person Omid; 02.02.2020