I have this code:
fn make_guess() -> u32 {
loop {
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("Failed to read line");
match guess.trim().parse() {
Ok(num) => return num,
Err(_) => {
println!("Please input a number!");
continue;
}
};
break;
}
}
When I run this code, the compiler complains about:
expected `u32`,
found `()`
Seemingly the break;
results in this returning a void value. However, there is no way for the break;
to be reached because of the return
and continue
.
In fact, if I remove the break;
this works fine.
Is this a bug in the compiler or intended for some reason?
答案 0 :(得分:4)
A loop
expression that doesn't contain a break
expression evaluates to !
(i.e. it diverges), so it is compatible with all types.
fn main() {
let _x: u32 = loop {}; // this compiles
}
On the other hand, a loop
with a break
returns ()
, so it is only compatible with the ()
type.
fn main() {
let _x: u32 = loop { break; }; // mismatched types: expected `u32`, found `()`
}
In your make_guess
function, the compiler adds an implicit return
before the loop
expression. !
is compatible with u32
, but ()
is not. (This implicit return
seems to occur for all diverging expressions, even if they end with a ;
.) Adding a break
statement in the loop changes the type of the loop
expression. It does not matter that the break
is unreachable.
Heads up to @ker for noticing that the type of a loop
changes based on the presence or absence of a break
expression in its body.
答案 1 :(得分:1)
问题是您的代码可能不会返回u32
。保持代码习惯生锈的最佳方法是使返回类型为Option<T>
这是一个包含两个成员Some(T)
和None
的枚举,这意味着该函数可以,或者可能不会返回值。
fn make_guess() -> Option<u32> {
loop {
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.ok()
.expect("Failed to read line");
match guess.trim().parse() {
Ok(num) => return Some(num),
Err(_) => {
println!("Please input a number!");
continue;
}
};
break;
}
None
}