3

I'm trying to write a general function that takes an iterable (or iterator) and iterates it twice, at least once mutably, like:

fn f(iter: I) where I: Iterator<Item = &mut i32> + Clone { for i in iter.clone() { println!("{}", *i); } for i in iter.clone() { *i += 1; } } 

But it doesn't work because mutable iterators tend not to have clone() implemented, and for just reasons. My real world example is iteration over HashMap values, where std::collections::hash_map::ValuesMut is not Clone. Are there any ways to do it?

5
  • Is there a reason you can't obtain the iterator twice from the map? Commented Mar 6, 2022 at 23:40
  • @ChayimFriedman because if borrow checker, from each iterator I can obtain a reference to e.g. 1. element, and therefore if I have two iterators I could have two references to the same element, one of which I want mutable. Commented Mar 6, 2022 at 23:51
  • @Dekakaruk I think he is referring more to how you can instead pass in &mut HashMap<K, V> or ValuesMut<'_, K, V> and use it more than once to create an iterator. Commented Mar 6, 2022 at 23:53
  • @Locke I can't do that because this is only one of possible sources, and actually even here I do hash_map.values_mu().flatten(), which changes types Commented Mar 7, 2022 at 0:01
  • If the problem is only code repetition, you can extract it into a function (or closure). Commented Mar 7, 2022 at 0:02

1 Answer 1

3

Unfortunately you are unable to do this. You will either need to merge them into a single for loop or save the items from the iterator to iterate over them again later.

The closest thing I could come up with is to use IntoIterator to require that the argument can be used to make a new iterator multiple times.

pub fn foo<'a, T>(iter: &'a mut T) where for<'b> &'b mut T: IntoIterator<Item=&'a mut i32> { for i in iter.into_iter() { println!("{}", *i); } for i in iter.into_iter() { *i += 1; } } let mut map = HashMap::new(); map.insert(2, 5); map.insert(6, 1); map.insert(3, 4); foo(&mut map.values_mut()) 

However, it seems like much less of a headache for you if you just pass a reference to the entire map.

pub fn bar<T>(map: &mut HashMap<T, i32>) { for i in map.values() { println!("{}", *i); } for i in map.values_mut() { *i += 1; } } 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, it works. I cannot use the non-generic solution because the iterator will come from various places with different types.
The generic version does not work: play.rust-lang.org/…. The iterator is exhausted after the first loop, all further calls to into_iter produce an empty iterator.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.