How do I enumerate a Vec of structs


#1

I want to iterate over a Vec of structs. I can iterate without enumerating.

#[derive(Debug)]
struct Pair<'a> {
    key: &'a str,
    value: &'a str,
}

fn main() {
    let mut pairs = Vec::new();
    for key in ["A", "B", "C", "D"].iter() {
        pairs.push(Pair { key, value: "even" });
        pairs.push(Pair { key, value: "odd" });
    }
    println!("{:?}", pairs);
    for pair in &pairs {
        println!("key={} value={}", pair.key, pair.value);
    }
    // All above this works fine: below produces errors
    /*
    for (i, pair) in &pairs.iter().enumerate() {
        println!("{}: key={} value={}", i, pair.key, pair.value);
    }
    */
}

The above compiles & runs fine. But if you uncomment the last for loop, it produces these errors:

error[E0277]: the trait bound `&std::iter::Enumerate<std::slice::Iter<'_, Pair<'_>>>: std::iter::Iterator` is not satisfied
  --> src/main.rs:18:5
   |
18 | /     for (i, pair) in &pairs.iter().enumerate() {
19 | |         println!("{}: key={} value={}", i, pair.key, pair.value);
20 | |     }
   | |_____^ `&std::iter::Enumerate<std::slice::Iter<'_, Pair<'_>>>` is not an iterator; maybe try calling `.iter()` or a similar method
   |
   = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate<std::slice::Iter<'_, Pair<'_>>>`
   = note: required by `std::iter::IntoIterator::into_iter`

I’ve tried use std::iter::{Iterate, Enumerate} in case I needed these traits, but that didn’t help.

Can someone tell me what I doing wrong please? (I know I could easily have a counter variable, but I really want to understand & do it right.)


#2

This case is as simple as removing the &.
for (i, pair) in pairs.iter().enumerate() {
& is the latter item to be evaluated and creates a reference to the Enumerate iterator. It works in the first &pairs loop by this making a slice which supports into iterator.
A more complex case might also require the use of ref keyword.


#3

If you want to iterate over the slice, so that the iterator does not take ownership of the Vec, you should add parenthesis like for (i, pair) in (&pairs).iter().enumerate() {


#4

Thanks!


#5

That’s unnecessary - iter() takes &self and thus doesn’t consume the Vec (compiler will insert an auto-ref to make the &self for the call).


#6

I tried &pairs & it didn’t work; but (&pairs) works fine. I’m using Rust 1.24.


#7

@mark, @jonh gave you the right formulation earlier, which I’ll repeat here:

for (i, pair) in pairs.iter().enumerate() {
   println!("{}: key={} value={}", i, pair.key, pair.value);
}

#8

@vitalyd – you are quite right! I’d misunderstood. That works perfectly & is of course much nicer.

Thanks!


#9

I’m sorry. Confused with into_iter()