Type of `std::iter::Map`?

Any suggestion as to how to label the type of std::iter::Map. I know closures are unnamable types, but what if I use an ordinary function? Is there any way to give the time of a map on an iterator?

Functions also have unnameable types, but both functions and captureless closures can coerce to function pointer types, fn(T) -> U. For example:

fn foo() -> std::iter::Map<std::vec::IntoIter<i32>, fn(i32) -> bool> {
    vec![1,2,3,4].into_iter().map(|x| x > 3)
}

Note that this can affect code generation, because (unless it gets optimized away) this involves dispatching through a function pointer, unlike the original zero-sized closure or function type. Leaving the type unnamed does not have this problem:

fn foo() -> impl Iterator<Item=bool> {
    vec![1,2,3,4].into_iter().map(|x| x > 3)
}
1 Like

Another approach is to create your own map iterator. This way you can hardcode the closure in the next method.

struct MyMap<I> {
    inner: I,
}

impl<I: Iterator<Item = u32>> Iterator for MyMap<I> {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        self.inner.next().map(|i| 2*i)
    }
}

playground

Besides being verbose, this unfortunately has the disadvantage that you have to manually add extra iterator features such as size_hint and impls such as DoubleEndedIterator, ExactSizeIterator and TrustedLen if you use the iterator in a context where these are important.

3 Likes

Importantly, you lose TrustedLen and this disables a whole bunch of optimizations (related to collect) that can't be brought back. (TrustedLen is private to std)

2 Likes

Is there any way around this? I can't see a solution other than writing my own version of Map, which has all the above problems, or perhaps using a dyn Iterator, which introduces it's own runtime cost.

You can use the impl Iterator syntax that @mbrubeck suggested

1 Like

Alas, that won't work for implementing IntoIterator. I use it for my other iterators, but can't do it for that one. :frowning:

Yes, that is unfortunate.

If you are willing to use nightly, you can use existential_types to get a zero cost solution.

TrustedLen is not private to std.

Also, as far as collect, the default implementation literally just just calls from_iter through the generic result type, which doesn't inherently involve TrustedLen at all.

2 Likes

It's not available in std without unstable at least..

As for collect, it uses specialization implementations to allow FromIterator::from_iter to detect TrustedLen in the generic impl. This is a nightly only feature, but the standard library is still allowed to use it in stable because it's special. See also here.

2 Likes

Huh, looks like I misremembered. Thanks for the correction.

1 Like