Using Iterators to produce more output values than inputs

I want to iterate over a data source and produce more then one entry in the resulting iterator for each input value.

This is a heavily reduced example of my problem:

led_values.extend(iter.flat_map(
    |x: u64| [x as u16, x as u16, x as u16].into_iter()
));

That gives me:

error[E0597]: borrowed value does not live long enough
   --> src/main.rs:156:75
  |
2 | |x: u64| [x as u16, x as u16, x as u16].into_iter()
  |          ------------------------------           ^ temporary value dropped here while still borrowed
  |          |
  |          temporary value created here
3 | ));
  |  - temporary value needs to live until here

After hours of investigations I think I've now understood why this happens: into_iter is only implemented for &[T; N] and not [T; N] - which was completely unexpected to me!

Why is into_iter not implemented for [T; N]?
How can I solve the actual problem of mapping a single value to multiple result values?

Thanks for any hints!

Check out the discussion of this limitation in RFC 2185. For now you need to pick some other iterator type to return in flat_map. For example Vec's iterator would work.

led_values.extend(iter.flat_map(
    |x: u64| vec![x as u16, x as u16, x as u16]
));
1 Like

Thanks for pointing out the discussion.

The workaround involves frequent heap allocations, which I cannot afford in my case. Or will they be optimized out by the compiler?

The zero allocation way would be to come up with your own iterator type. Playground

Or pick any standard library iterator that does not allocate. Playground

I'd recommend using ArrayVec from the arrayvec crate.

led_values.extend(iter.flat_map(
    |x: u64| ArrayVec::from([x as u16, x as u16, x as u16])
));

should work?

It's like Vec, but stack based. It doesn't support all sizes, but it should support everything up to length 32, and it has a consuming IntoIterator just as Vec does.

ArrayVec<[u16; 3]> does have overhead compared to [u16; 3], but that overhead is a single usize representing the number of elements stored.

2 Likes

That seems to be the best solution until const generics have landed (which seems to block RFC 2185).

1 Like