There are two sets of checks happening here, which is why the difference appears confusing.
-
Each type in the function signature is checked for validity.
Optioninherently requiresT: Sized. A return type that doesn’t requireSizedis fine:trait Works { fn foo() -> Box<Self>; }The existing answer covers this well.
-
Any function with a body also checks that all of the parameters are
Sized. Trait functions without a body do not have this check applied.Why is this useful? Allowing unsized types to be used in trait methods is a key part of allowing by-value trait objects, a very useful feature. For example,
FnOncedoes not require thatSelfbeSized:pub trait FnOnce<Args> { type Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output; }fn call_it(f: Box<dyn FnOnce() -> i32>) -> i32 { f() } fn main() { println!("{}", call_it(Box::new(|| 42))); }
A big thanks to pnkfelix and nikomatsakis for answering my questions on this topic.