The lifetimes and return types should be compatible even though the concrete iterator types are different.
As I understand impl Trait in return position is that it’s simply the promise “some type that implements Trait”. So why does the compiler complain about this?
In return position it doesn’t indicate, “Some type that implements this trait”, rather, it indicates, “Some SPECIFIC CONCRETE type that implements this trait”. In other words, you are not naming the type specifically, but, it is some specific type that is being returned. In your case inner_zero and inner_one are not guaranteed to return the same specific type, so they both can’t be the return type of iter because then iter would not have a specific return type. If you want to return just something that is the given trait, then, you need to return a Box<dyn Trait> instead (dynamic dispatch) instead of impl Trait (static dispatch).
Put another way, impl Trait in return position is “Existential”, whereas Box<dyn Trait> is “Universal”. (see Wikipedia for defs of these terms).
@DanielKeep@gbutler69 yeah I was afraid of that.
The problem is that I am trying to reduce heap allocation, not increase it.
The code in the example can run in the body of several nested several loops, so allocation quickly becomes really expensive.
So I guess I’ll have to find another solution, thanks anyway
For iterators specifically, just accepting a callback (i.e, “internal iteration”) or even just an buf: &mut Vec<Item> often works well.
And for some cases, like iterating over a tree, you might need some form of heap allocation for external iterators, while internal iterators can use stack space via recursion.
This solution does a pretty nice job of abstracting over the 2 different iterators. Either's internal magic even allows me to treat the return type of Foo::iter() itself as an iterator, which is ideal both because it does wat the name iter implies and because I can continue to leverage the impl Trait syntax.