What does a trait requiring Sized have to do with being unable to have trait objects of that trait?

好久不见. 提交于 2020-04-13 03:54:11

问题


I have this code (playground):

trait NodeLike: Sized {}

fn main() {
    let s: Box<NodeLike> = panic!();
}

Which does not compile:

error[E0038]: the trait `NodeLike` cannot be made into an object
 --> src/main.rs:4:12
  |
4 |     let s: Box<NodeLike> = panic!();
  |            ^^^^^^^^^^^^^ the trait `NodeLike` cannot be made into an object
  |
  = note: the trait cannot require that `Self : Sized`

After all I read, I still don't understand why it does not compile and why it does without the Sized constraint.

As far as I know:

  • Box<NodeLike> is treated as Box<dyn NodeLike> which uses dynamic dispatch for method calls.
  • Box<NodeLike> is sized anyways, regardless of its item type.
  • The sized/unsized theory is necessary because there are types whose size is not known upfront (like arrays or strings).
  • The Sized marker on traits enforces implementing types to be sized.

What does requiring that implementing types are Sized have to do with not being able to have objects (with dynamic dispatch) of that trait?


回答1:


Having Self: ?Sized on the trait type itself is a required property for a trait object, i.e. for 'object safety', even though you can have an impl on a Self: ?Sized trait with a Sized type. Hence confusion.

It's a drawback that was decided upon in RFC 255 which deals with object safety (warning: obsolete Rust syntax).

It's a long read, but one of the alternatives was to determine 'object safety' by only analyzing the methods of the trait. It is admitted in the RFC that having this restriction will make some code that could have worked not to compile. ("This is a breaking change and forbids some safe code which is legal today.").

We can go around this if we lower the restriction only to the trait members function that actually need it, e.g. this compiles:

trait NodeLike {
    fn method_foo(&self) -> Self where Self : Sized;
}

fn main() {
    let s: Box<NodeLike> = panic!();
    // Compiles!
}

However, we cannot call those Self: Sized methods via a trait object, and this is a limitation that is explained elsewhere. Here, calling s.method_foo(); will break compilation.

Note that the Self: Sized constraint limits compilation even if the method does not make use of Self at all and could have been a callable trait object method otherwise.



来源:https://stackoverflow.com/questions/53987976/what-does-a-trait-requiring-sized-have-to-do-with-being-unable-to-have-trait-obj

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!