Borrowing from data the iterator owns while iterating

I would like to be able to iterate over a series of owned items whole also getting a reference to an item owned by the iterator.

Like this (code doesn't compile because the lifetimes are missing, but it shows what I'd like to achieve):

use std::collections::HashMap;

struct Things {
    things: Vec<String>,
    singleton: HashMap<String, String>,
}

struct ThingsIntoIterator {
    things: std::vec::IntoIter<String>,
    singleton: HashMap<String, String>,
}

impl IntoIterator for Things {
    type Item = (String, &HashMap<String, String>); // lifetimes?
    type IntoIter = ThingsIntoIterator;

    fn into_iter(self) -> Self::IntoIter {
        ThingsIntoIterator {
            things: self.things.into_iter(),
            singleton: self.singleton
        }
    }
}

impl Iterator for ThingsIntoIterator {
    type Item = (String, &HashMap<String, String>); // here as well

    fn next(&mut self) -> Option<Self::Item> {
        self.things.next().map(|thing| (thing, &self.singleton))
    }
}

Where the iterator consumer gets each String from things owned and a reference to singleton for as long as the iterator is alive. I don't want to just iterate over things and reference singleton in map and co closures because I would like to transfer ownership of ThingsIntoIterator to someone else consuming it. I think that this should be possible, I just don't know how to express the lifetimes of the GATs to tell Rust that the hashmap reference points to ThingsIntoIterator.

This is something the Iterator trait cannot provide. Because the Item doesn't have a lifetime parameter and so it cannot reference data borrowed from &mut self.

trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>
}

You will need to implement a lending iterator pattern:

pub trait LendingIterator {
    type Item<'a>
    where
        Self: 'a;

    fn next(&mut self) -> Option<Self::Item<'_>>;
}

Note that the above example shows how a minimal lending iterator trait could work, but in practice, GATs are too restrictive (expressing bounds on the associated Item<'_> is difficult). I like the approach employed by the lender crate[1].


  1. lender is unsound for other reasons, so even though its polyfill for better GATs is great, I wouldn’t necessarily recommend using lender. ↩︎