Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get a "match arms have incompatible types" error in a function returning `impl Trait`?

Tags:

rust

trait Counter {
    fn count(&self) -> i32;
}

struct AddCounter {
    a: i32,
    b: i32,
}
impl Counter for AddCounter {
    fn count(&self) -> i32 {
        self.a + self.b
    }
}

struct MulCounter {
    a: i32,
    b: i32,
}
impl Counter for MulCounter {
    fn count(&self) -> i32 {
        self.a * self.b
    }
}

fn get_counter(a: i32, b: i32, op: &str) -> impl Counter {
    match op {
        "+" => AddCounter { a, b },
        "*" => MulCounter { a, b },
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

fn main() {}

I get an error when I call get_counter(...):

error[E0308]: match arms have incompatible types
  --> src/main.rs:26:5
   |
26 | /     match op {
27 | |         "+" => AddCounter { a, b },
28 | |         "*" => MulCounter { a, b },
   | |                ------------------- match arm with an incompatible type
29 | |         _ => panic!(format!("{}{}", "未知的符号:", op)),
30 | |     }
   | |_____^ expected struct `AddCounter`, found struct `MulCounter`
   |
   = note: expected type `AddCounter`
              found type `MulCounter`
like image 869
刘林欣 Avatar asked Jul 26 '18 16:07

刘林欣


1 Answers

See the impl Trait notation as a generic type. You cannot write:

fn get_counter<T>(a: i32, b: i32, op: &str) -> T {
    match op {
        "+" => AddCounter { a, b },
        "*" => MulCounter { a, b },
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

because AddCounter and MulCounter do not have the same type: what is T?

You can use dynamic dispatch instead of static dispatch:

fn get_counter(a: i32, b: i32, op: &str) -> Box<dyn Counter> {
    match op {
        "+" => Box::new(AddCounter { a, b }),
        "*" => Box::new(MulCounter { a, b }),
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

Further explanation

When you use static dispatch, the Rust compiler monomorphizes the code: it generates a new function for each value of the generic type (see What is monomorphisation with context to C++? for more details). Each of those returned values are "real" plain types. In this case, a function cannot return (for example) a String in one path and an i32 in another path.

In the case of dynamic dispatch, it is not the "real" type that is returned but a trait object: the compiler does not know the real type; it only cares that the trait object can be used as a trait implementor. That is what you need here.

like image 195
Boiethios Avatar answered Sep 18 '22 13:09

Boiethios