Reputation: 11817
I'm reading The Rust Programming Language book and I stumbled upon a simple expression:
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
How does match
work with different kinds of expressions in its arms? E.g. the first arm would simply "return" num
so that it's assigned to guess
but in the second arm the expression is simply continue
. How does match
handle that and doesn't "assign" continue
to guess
but executes it? What happens with the whole assignment expression itself? Is it dropped from the call stack (if that's the correct term)?
Upvotes: 6
Views: 1948
Reputation: 71390
continue
has a special type: it returns the never type, denoted !
.
This type means "the code after that is unreachable". Since continue
jumps to the next cycle of the loop, it'll never actually return any value (the same is true for return
and break
, and it's also the return type of panic!()
, including all macros that panic: unreachable!()
, todo!()
, etc.).
The never type is special because it coerces (converts automatically) to any type (because if something cannot happen, we have no problems thinking about it as u32
or String
or whatever - it will just not happen). This means it also unify with any other type, meaning the intersection of any type and !
is the other type.
match
requires the expressions' type to unify (as does if
). So your code returns the unification of !
and u32
== u32
.
You can see that if you'll denote the type (requires nightly, since using the !
type not at return type position is experimental):
let num = match num {
Ok(num) => {
let num: i32 = num;
num
}
Err(()) => {
let never: ! = continue;
never
}
};
Upvotes: 11