From `Iterator<Item = T>` to `Iterator<Item = &T>`

I have an Iterator<Item = u32> but my function takes an I: Iterator<Item = &u32>. Is there a way to "downgrade" my iterator to borrow the data instead of owning it? iter.map(|i| &i) doesn't work:

70 |         let borrowed = iter.map(move |c| &c);
   |                                          ^^ returns a reference to data owned by the current function

Not really, since an Iterator can only "yield' values one by one and once the value is produced, it is, sort of, dis-associated with the iterator. So there is no real way to get a reference to the element.
On the other hand, if you can afford the storage, then you can iterator.collect::<Vec<_>>().iter().

1 Like

If you control the function taking I: Iterator<Item = &u32>, I suggest

  • Changing it to take I: Iterator<Item = u32>
  • Fixing everything that broke by adding a call to .copied()

As the latter step is a simple way to go the opposite direction.

3 Likes

It's good to take a step back here and thing about what borrowing means. When you're borrowing something, it's because it exists somewhere. If it doesn't exist anywhere, you can't borrow it.

An Iterator<Item = u32> promises to give you u32s when you ask for them. But they don't exist anywhere else -- it might be a Range<u32>, for example, which doesn't have a bunch of owned things sitting around in memory somewhere, it just creates them when needed.

So you fundamentally can't just write a stateless lazy adapter that turns owned values into borrowed ones. You'd have to store them somewhere from which you can borrow them -- such as collecting them into a Vec<u32>, then getting the .iter() that gives out borrows of those items.

Thus as @quinedot said, the best solution here is to update your function to take owned items from the iterator. For trivial Copy types like u32, it's easier (and probably better performance, too!) to not bother with immutable borrows.

6 Likes