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`
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)),
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With