Я читаю книгу 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(())
}
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
/!
для получения дополнительной информации)
Обратите внимание, что результат
match
привязан кnumber
. Каким может быть типnumber
? В вашей версии результат совпадения может быть либо типаi32
, либоResult
, а типnumber
может быть только тем или иным, выбранным во время компиляции.