Reputation: 2657
When trying to return a trait object from a default implementation within a trait, such as
trait Foo {
fn foo(self: Box<Self>) -> Box<dyn Foo> {
self
}
}
the Rust compiler complains that
error[E0277]: the size for values of type `Self` cannot be known at compilation time
note: required for the cast to the object type `dyn Foo`
The type cast should be from Box<Self>
to Box<dyn Foo>
, why would this require Self to be sized?
Upvotes: 2
Views: 79
Reputation: 10317
It's impossible to convert an unsized type to trait object, since this will force it to have two sets of metadata at once.
Consider this code:
trait Foo: 'static {
fn foo(self: Box<Self>) -> Box<dyn Foo> {
self
}
}
trait Bar {}
impl Foo for dyn Bar {}
impl Foo for i32 {}
impl<T> Bar for T {}
fn main() {
let boxed = Box::new(42);
boxed.foo();
let boxed: Box<dyn Bar> = Box::new(42);
boxed.foo();
}
In this case, there's nothing which would forbid the last call - all the signatures allow it. But, if we coerce Box<dyn Bar>
to Box<dyn Foo>
, where would the virtual functions table for dyn Bar
go? (It's empty in this case, of course, but it still have to exist - empty traits are not special)
If you add where Self: Sized
to foo
, however, the last call is properly rejected:
error: the `foo` method cannot be invoked on a trait object
--> src/main.rs:20:11
|
2 | fn foo(self: Box<Self>) -> Box<dyn Foo> where Self: Sized {
| ----- this has a `Sized` requirement
...
20 | boxed.foo();
| ^^^
Upvotes: 5