Reputation: 43
I'm trying to create a kind of wrapper trait that combines multiples traits and a function that return 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
I am aware of how to combine traits :
Is there a way to combine multiple traits in order to define a new trait?
Is there any way to create a type alias for multiple traits?
But unfortunately, I've not found anything with associated types
Here is a summarized example of where I'm stucked
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)
}
}
trait HelloGoodbye: Hello + Goodbye {}
impl<T> HelloGoodbye for T where T: Hello + Goodbye {}
fn get_hello_goodbye() -> Box<dyn HelloGoodbye> {
Box::new(World::new("Everyone".to_string()))
}
trait SuffixableHello: Hello + Add<Suffix, Output = Self> {}
impl<T> SuffixableHello for T where T: Hello + Add<Suffix, Output = Self> {}
fn get_suffixable_hello() -> Box<dyn SuffixableHello> {
Box::new(World::new("Everyone".to_string()))
}
fn main() {
// This works
let hello_goodbye = get_hello_goodbye();
hello_goodbye.hello();
hello_goodbye.goodbye();
// This does not work
let suffixable_hello = get_suffixable_hello();
suffixable_hello.hello()
}
I got this compilation error :
49 | fn get_suffixable_hello() -> Box<dyn SuffixableHello> {
| ^^^^^^^^^^^^^^^ help: specify the associated type: `SuffixableHello<Output = Type>`
What am I supposed to put there ?
What I've try so far :
trait SuffixableHello<T>: Hello + Add<Suffix, Output = T> {}
impl<T, U> SuffixableHello<T> for T where T: Hello + Add<Suffix, Output = Self> {}
And I get
|
49 | fn get_suffixable_hello() -> Box<dyn SuffixableHello<T>> {
| ~~~~~~~~~~~~~~~~~~
Where am I supposed to add this T
generic ? Does my fucntion need to be generic ?
trait SuffixableHello: Hello + Add<Suffix> {}
impl<T> SuffixableHello for T where T: Hello + Add<Suffix, Output = T> {}
But I get :
the value of the associated type `Output` (from trait `Add`) must be specified
This makes sense since Output is not declared in the trait.
World
by Self
in the impl Add<Suffix> for World
Am I missing something here ? Thank you
Also, what if we want to return from the get_suffixable_hello()
one of two Hello
implementations, let's say World
and World2
to cite @cadolphs like in this doc https://doc.rust-lang.org/rust-by-example/trait/dyn.html
Upvotes: 1
Views: 812
Reputation: 9657
fn get_suffixable_hello() -> Box<dyn SuffixableHello<Output=World>> {
Box::new(World::new("Everyone".to_string()))
}
does the trick.
EDIT: Longer explanation. Your first initial compiler error tells you that you can't just return Box<dyn SuffixableHello>
. That's because having the same trait but with different associated types isn't allowed, because the signatures of associated methods would be different.
So. We need to put a type there. And what should that type be? Well, given that you're explicitly calling World::new
, there's really only one type that makes sense here, and that's World
.
In your toy example that makes it of course a bit silly and redundant because there's only one struct that implements all those traits.
If you had another struct, World2
, you could not have it be returned by get_suffixable_hello
next to World
, because World2
would have associated type Output=World2
and hence
wouldn't match the Output=World
associated type.
Upvotes: 1