I have a trait that has "adapter methods" that consume the method:
struct Bar<T>(T);
trait Foo {
fn make_bar(self) -> Bar<Self>
where
Self: Sized,
{
Bar(self)
}
}
impl Foo for u8 {}
impl Foo for bool {}
This is modeled after Iterator
. When I use a Box<Iterator>
, I can still call Iterator
adapter methods like map
or filter
:
fn main() {
let a = vec![1, 2, 3];
let b: Box<Iterator<Item = u8>> = Box::new(a.into_iter());
let c = b.map(|x| x * 2);
for z in c {
println!("{}", z)
}
}
However, the methods I've defined don't work in the same way:
fn main() {
let a: Box<Foo> = Box::new(42);
a.make_bar();
}
This fails with the errors
error[E0277]: the trait bound `Foo: std::marker::Sized` is not satisfied
--> src/main.rs:18:7
|
18 | a.make_bar();
| ^^^^^^^^ `Foo` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Foo`
It's absolutely correct that Foo
does not have a size - it's a trait. However, Box<Foo>
should have a size, as I understand it. What is Iterator
doing differently from my code?
Because Iterator
is object safe, the trait object Iterator
implements Iterator
.
Because impl<I: Iterator + ?Sized> Iterator for Box<I>
, the boxed trait object Box<Iterator>
implements Iterator
.
Thus in your case the solution is to implement Foo
for Box<Foo>
. This could be generic like Iterator
’s (impl<T: ?Sized + Foo> Foo for Box<T> { }
) or it could be specific (impl Foo for Box<Foo> { }
).
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