Your mistake is that you think you call <dyn Iterator<Item = ()>>::for_each()
, and then you wonder rightfully how you can if for_each()
requires Self: Sized
but dyn Iterator<Item = ()>
is obviously not Sized
. But you are wrong. And you can see that if you'll use UFCS (Universal Function Call Syntax):
#[test]
#[should_panic]
fn trait_obj() {
let mut v: Vec<Box<dyn Iterator<Item = ()>>> = vec![];
// v.remove(0).for_each(|_| {});
<dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
}
Playground.
Emits:
error[E0277]: the size for values of type `dyn Iterator<Item = ()>` cannot be known at compilation time
--> src/lib.rs:7:5
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = ()>`
note: required by a bound in `for_each`
error[E0308]: mismatched types
--> src/lib.rs:7:41
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^ expected trait object `dyn Iterator`, found struct `Box`
|
= note: expected trait object `dyn Iterator<Item = ()>`
found struct `Box<dyn Iterator<Item = ()>>`
help: consider unboxing the value
|
7 | <dyn Iterator<Item = ()>>::for_each(*v.remove(0), |_| {});
| +
error[E0277]: the size for values of type `dyn Iterator<Item = ()>` cannot be known at compilation time
--> src/lib.rs:7:41
|
7 | <dyn Iterator<Item = ()>>::for_each(v.remove(0), |_| {});
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = ()>`
= note: all function arguments must have a statically known size
And this error also hints you why the previous version worked: you didn't call <dyn Iterator<Item = ()>>::for_each()
, you called Box::<dyn Iterator<Item = ()>>::for_each()
! Box<Iterator>
implements Iterator
itself, and so it worked. You can see that explicitly in the MIR:
v.remove(0).for_each(|_| {});
// Snip
_2 = <Box<dyn Iterator<Item = ()>> as Iterator>::for_each::<[closure@src/lib.rs:4:26: 4:32]>(move _3, move _5) -> [return: bb3, unwind: bb5];
// Snip
Playground (choose "Show MIR" from the menu).
If you has had implemented Observable
for Box<O> where O: Observable
, it would work for you too...
...Except you cannot. Because you cannot forward the call to for_each()
. The reason it works with Iterator
is that it does not forward this call, and rather uses the default implementation that calls next()
again and again. And because next()
takes &mut self
, it doesn't require Self: Sized
.