Любой способ сделать unwrap_or_return, чтобы сделать ранний возврат - PullRequest
0 голосов
/ 02 февраля 2020

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

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

    let second_number = match second_number_str.parse::<i32>() {
        Ok(n) => n,
        Err(_) => return -2,
    };

    first_number * second_number
}

fn main () {
    assert_eq!(2, multiply("1", "2"));
    assert_eq!(-1, multiply("a", "2"));
    assert_eq!(-2, multiply("1", "b"));
    assert_eq!(-1, multiply("a", "b"));
}

(детская площадка)

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

fn multiply(first_number_str: &str, second_number_str: &str) -> i32 {
    let first_number = first_number_str.parse::<i32>().unwrap_or_return(-1);
    let second_number = second_number_str.parse::<i32>().unwrap_or_return(-2);

    first_number * second_number
}

fn main () {
    assert_eq!(2, multiply("1", "2"));
    assert_eq!(-1, multiply("a", "2"));
    assert_eq!(-2, multiply("1", "b"));
    assert_eq!(-1, multiply("a", "b"));
}

Если нет прямого пути, каковы лучшие практики для этого?

Ответы [ 2 ]

3 голосов
/ 02 февраля 2020

Становится проще, если тип возвращаемого значения не i32, а Result<i32, SomeErrorType>.

В этом случае вы можете использовать знак вопроса, чтобы получить что-то вроде этого:

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, i32> {
    let first_number = first_number_str.parse::<i32>().map_err(|_| -1)?;
    let second_number = second_number_str.parse::<i32>().map_err(|_| -2)?;

    Ok(first_number * second_number)
}

fn main () {
    assert_eq!(Ok(2), multiply("1", "2"));
    assert_eq!(Err(-1), multiply("a", "2"));
    assert_eq!(Err(-2), multiply("1", "b"));
    assert_eq!(Err(-1), multiply("a", "b"));
}

Если бы я делал это, я бы, вероятно, go с этим кодом. Излишне говорить, что я бы не использовал Result<i32, i32>, а вместо Result<i32, CustomErrorTypeDenotingIfProblemIsAOrB>. Возможно, я бы даже сохранил тип ошибки parse, пропустив map_err.

Вот информация об операторе вопросительного знака.

Если вы настаиваете на сохраняя в качестве возвращаемого значения i32, Result предлагает множество различных методов, которые могут помочь достичь чего-то похожего на вашу цель. Тем не менее, я не знаю ни одного, канонического способа сделать это, поэтому я мог бы взглянуть на and_then, map_err и др.

Редактировать: Я просто понял, что это на самом деле предлагается в следующей главе .

0 голосов
/ 02 февраля 2020

Или вы можете переписать его в функциональном стиле, используя Result :: map_or:

fn multiply(first_number_str: &str, second_number_str: &str) -> i32 {
    first_number_str.parse::<i32>().map_or(-1, |first| { 
        second_number_str.parse::<i32>().map_or(-2, |second| first*second)
    })
}
...