I'm trying to create a kind of wrapper trait that combines multiples traits and a function that is in a factory pattern fashion that returns the associated implementation of the trait. It works well as long as you don't have associated types. I don't know how to refer to the Output
type
use std::ops::Add;
pub trait Hello {
fn hello(&self);
}
pub trait Goodbye {
fn goodbye(&self);
}
struct Suffix {
suffix: String,
}
pub struct World {
content: String,
}
impl World {
fn new(content: String) -> Self {
World { content: content }
}
}
impl Hello for World {
fn hello(&self) {
println!("Hello {}", self.content)
}
}
impl Goodbye for World {
fn goodbye(&self) {
println!("Goodbye {}", self.content)
}
}
impl Add<Suffix> for World {
type Output = World;
fn add(self, other: Suffix) -> World {
let suffixed: String = self.content + &other.suffix;
World::new(suffixed)
}
}
pub struct Everyone {
content: String,
}
impl Everyone {
fn new(content: String) -> Self {
Everyone { content: content }
}
}
impl Hello for Everyone {
fn hello(&self) {
println!("Hello {}", self.content)
}
}
impl Goodbye for Everyone {
fn goodbye(&self) {
println!("Goodbye {}", self.content)
}
}
impl Add<Suffix> for Everyone {
type Output = Everyone;
fn add(self, other: Suffix) -> Everyone {
let suffixed: String = self.content + &other.suffix;
Everyone::new(suffixed)
}
}
trait HelloGoodbye: Hello + Goodbye {}
impl<T> HelloGoodbye for T where T: Hello + Goodbye {}
fn get_hello_goodbye(number: f64) -> Box<dyn HelloGoodbye> {
if number > 0.5 {
Box::new(World::new("World".to_string()))
} else {
Box::new(Everyone::new("Everyone".to_string()))
}
}
trait SuffixableHello: Hello + Add<Suffix, Output = dyn Hello> {}
impl<T> SuffixableHello for T where T: Hello + Add<Suffix, Output = dyn Hello> {}
fn get_suffixable_hello<T: SuffixableHello>(number: f64) -> Box<dyn SuffixableHello> {
if number > 0.5 {
Box::new(World::new("World".to_string()))
} else {
Box::new(Everyone::new("Everyone".to_string()))
}
}
fn main() {
// This works
let hello_goodbye = get_hello_goodbye(0.64f64);
hello_goodbye.hello();
hello_goodbye.goodbye();
// This does not work
let suffixable_hello = get_suffixable_hello(0.64f64);
suffixable_hello.hello()
}
I get this error :
error[E0271]: type mismatch resolving `<World as Add<Suffix>>::Output == (dyn Hello + 'static)`
|
81 | Box::new(World::new("World".to_string()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<World as Add<Suffix>>::Output == (dyn Hello + 'static)`
|
note: expected this to be `(dyn Hello + 'static)`
|
33 | type Output = World;
| ^^^^^
= note: expected trait object `(dyn Hello + 'static)`
found struct `World`
= note: required for the cast to the object type `dyn SuffixableHello<Output = (dyn Hello + 'static)>`
error[E0271]: type mismatch resolving `<Everyone as Add<Suffix>>::Output == (dyn Hello + 'static)`
|
83 | Box::new(Everyone::new("Everyone".to_string()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Everyone as Add<Suffix>>::Output == (dyn Hello + 'static)`
|
note: expected this to be `(dyn Hello + 'static)`
|
60 | type Output = Everyone;
| ^^^^^^^^
= note: expected trait object `(dyn Hello + 'static)`
found struct `Everyone`
= note: required for the cast to the object type `dyn SuffixableHello<Output = (dyn Hello + 'static)>`
Is this possible in rust ? I tried a lot of different combinations and none of them work. I know that I can handle those type inside an enum struct, but if we want to get the corresponding value from a function the return type is still a problem, no ?
Maybe it's a design problem, and this is not the way it should work in rust, if so, is there a better way to do ?
Thank you a lot