Почему `return` необходим в `match` руке при использовании `Result` в `main`?

Я читаю книгу Rust by Example. В этом пример удаление return в Err(e) => return Err(e) вызывает ошибку: expected `i32`, found enum `Result`` . Это почему?

В чем разница между Err(e) => return Err(e) и Err(e) => Err(e)?

Вот код из примера:

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let number_str = "10";
    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => return Err(e),
    };
    println!("{}", number);
    Ok(())
}

Обратите внимание, что результат match привязан к number. Каким может быть тип number? В вашей версии результат совпадения может быть либо типа i32, либо Result, а тип number может быть только тем или иным, выбранным во время компиляции.

Nate Eldredge 20.03.2022 04:01
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => return Err(e),
    };

Это говорит о том, что если number_str.parse::<i32>() возвращает Ok, чтобы установить number на number, i32. Если он возвращает Err для немедленного возврата Err(e), который является Result, из main, number не устанавливается.

Это нормально, потому что number может быть только i32, а main возвращает Result.

    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => Err(e),
    };

Это говорит о том, что если number_str.parse::<i32>() возвращает Ok, чтобы установить number на number, i32, как и раньше. Если он возвращает Err, чтобы установить number на Err(e), что является Result.

number не может быть одновременно i32 и Result, поэтому вы получите ошибку компиляции.

Все руки match должны иметь «совместимые» типы. Это означает, что все они имеют один и тот же тип:

fn is_some<T>(opt: &Option<T>) -> bool {
  match opt {
    // both arms have type bool
    Some(_) => true,
    None => false,
  }
}

или некоторым ветвям необходимо каким-то образом направить поток управления в сторону от совпадения.

Главное правило, которое следует держать в голове, заключается в том, что каждая переменная в Rust должна иметь тип Один (игнорируя дисперсию относительно времени жизни). В вашем случае, если бы у вас не было ключевого слова return, каким был бы тип number?

Если синтаксический анализ завершится успешно, number будет i32. Если это не удастся, это будет Err(ParseIntError). Это не разрешено, поэтому вы получите ошибку компиляции.

Однако, если вы return Err(e), number всегда будет i32 (поскольку return предотвращает выполнение остальной части функции, поэтому number не нужен тип).

То же самое относится и к другим ключевым словам потока управления (например, continue, break, ...), а также к вещам, которые гарантированно не возвращаются, например panic!() (ищите тип Never/! для получения дополнительной информации)

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