I'm trying to implement an AsBox<T>
trait such that functions requiring a boxed argument can also accept an owned value automatically.
Where T
is a concrete type it works fine: playpen example
However, where T
is a trait (which is the real reason for our function to accept a box, not an owned value), I can't get it to work. Is there any way to say that a template parameter is a trait?
playpen
@dhardy There are a few limitations here:
- There is no
Trait
trait implemented by all trait object types, so T: Trait
is right out.
- Even if there were,
T
would then be the raw trait object type associated with a given trait, not the trait itself, so S: T
would not be valid syntax.
So you just can't write this as a general impl rule for all trait objects. You can write this, specific to a given trait:
impl<'a, S> AsBox<fmt::Display + 'a> for Box<S> where S: fmt::Display + 'a {
fn as_box(self) -> Box<fmt::Display + 'a> { box *self }
}
Now, let's do the same thing for the final impl:
impl<'a, S> AsBox<fmt::Display + 'a> for S where S: fmt::Display + 'a {
fn as_box(self) -> Box<fmt::Display + 'a> { box self }
}
Once we've done this, we get conflicting impl errors. It turns out that this impl actually encompasses both Box<Display>
and Box<S> where S: fmt::Display
. You only need the one. Unfortunately, it reallocates the underlying trait object if you're passing a trait object. You can avoid this with specialization if its important to you.
This gives you what you want, but on a trait-by-trait basis. You could easily write a macro like as_boxed_trait!(Display);
to provide the impls that for each trait you want with less copy-pasting.
1 Like