Why does matching a Result require an explicit Err when changing the type of the Result?

  • A+
Category:Languages

I have a match expression that I would like to potentially return an error from. It seems that the compiler is not able to infer that the last case e is an Err(String) and requires the pattern to be explicit:

fn foo() -> Result<Option<u8>, String> {     unimplemented!() // don't mind the panic here }  fn foo2() -> Result<u8, String> {     let bar = foo();      for _ in 0..3 {         let baz = match bar {             Ok(Some(b)) => b,             Ok(None)    => continue,             Err(e)      => return Err(e) // works //          e           => return e      // error[E0308]         };     }      Ok(0) }  fn main() {     let _ = foo2(); } 

The error is:

error[E0308]: mismatched types   --> src/main.rs:13:33    | 13 |           e           => return e      // error[E0308]    |                                 ^ expected u8, found enum `std::option::Option`    |    = note: expected type `std::result::Result<u8, _>`               found type `std::result::Result<std::option::Option<u8>, _>` 

I'm pretty sure I have exhausted all the Ok(_) variants, so the only one left should be Err(_). This error doesn't occur if foo() returns Result<u8, String>, for instance. Am I missing anything?

 


Because Err is not a type.

Err is a variant of Result<T, E> whose type is Result<T, E>. Since Result<T, E> is different from Result<U, E> unless T == U, and since there is no implicit conversion, you need to explicitly perform the conversion.

I admit it does look silly since type inference takes care of deducing the T, U, and E in this case resulting in Err(e) => return Err(e), but at the semantic level those 2 Err(e) have different types.

For another silly example:

enum Term<'a> {     Int(i64),     String(&'a str), }  fn staticify(t: Term) -> Term<'static> {     use Term::*;      match t {         String(_) => String("Hello, World!"),         _ => t,     } } 

Will fail for the same reason, because Term<'a> and Term<'static> are not the same type unless 'a == 'static. When Term contains mostly non-lifetime parameters it gets tedious :(

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: