Consider the following simple program:
use std::process;
use std::fmt::Display;
fn fatal(message: impl Display) -> ! {
eprintln!("{}", message);
process::exit(1);
}
fn main() {
let x: Result<i32, &str> = Err("An error occurred");
println!("{}", x.unwrap_or_else(|err| fatal(err)));
}
It compiles, and running it produces the result of "An error occurred" being output to standard error, as expected.
However if I make the following ever-so-slight change to the program, changing main
to be:
fn main() {
let x: Result<i32, &str> = Err("An error occurred");
println!("{}", x.unwrap_or_else(fatal));
}
Then the program fails to compile, giving the following error message:
error[E0271]: type mismatch resolving `<fn(&str) -> ! {fatal::<&str>} as FnOnce<(&str,)>>::Output == i32`
--> src/main.rs:11:22
|
11 | println!("{}", x.unwrap_or_else(fatal));
| ^^^^^^^^^^^^^^ expected `!`, found `i32`
|
= note: expected type `!`
found type `i32`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.
I'm having trouble making sense of this. In the first version of the program (i.e. the one that compiles successfully) the closure returns a value of type Never
, which being the bottom-type, unifies with the otherwise expected i32
. This makes perfect sense. What is confusing to me is that despite (as far as I can tell) the second version of the program (i.e. the one that does not compile successfully) also producing a value of type Never
from unwrap_or_else
, just without the seemingly useless closure, it somehow fails to compile due to a type mismatch. I would greatly appreciate it if anyone could shed some light on this for me.