I was playing around with some API concepts and noticed something peculiar in Rust's Iterator trait.
I have the following trait definition:
trait Observable {
type Item;
fn subscribe<F>(self, f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) + 'static;
}
I then proceeded to write the following test:
#[test]
#[should_panic]
fn trait_obj() {
let mut v: Vec<Box<dyn Iterator<Item = ()>>> = vec![];
let mut v2: Vec<Box<dyn Observable<Item = Ref<u8>>>> = vec![];
v.remove(0).for_each(|_| {});
v2.remove(0).subscribe(|_| {});
}
The above test does not compile, as one would expect; subscribe() takes self by value, and has a Sized constraint on Self, therefore is not object safe.
However, if I comment out the ...subscribe line, it does compile!
The odd thing to me is, Iterator::for_each() has the same constraints. Why is this allowed for Iterator and not for Observable? Is it an experimental feature that enables this?
Here is the function signature of Iterator::for_each for reference:
// Iterator::for_each
fn for_each<F>(self, f: F)
where
Self: Sized,
F: FnMut(Self::Item);
The function signatures for Iterator::for_each and Observable::subscribe are pretty much identical.
What gives?