Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iteration over a struct vector

Tags:

rust

I have a struct that has a vector of another struct type.

struct Element {
    val: String,
}

struct Collection {
    elements: Vec<Element>,
}

impl Collection {
    fn process(&mut self) {
        for entry in &self.elements.iter_mut() {
            entry.val = "New value".to_string();
            println!("{}", entry.val);
        }
    }
}

fn main() {
    let e1 = Element {
        val: "My first entry".to_string(),
    };
    let e2 = Element {
        val: "My second entry".to_string(),
    };
    let mut c = Collection { elements: vec![] };
    c.elements.push(e1);
    c.elements.push(e2);
    c.process();
}

When I try to iterate over it, I get the following error:

error[E0277]: the trait bound `&std::slice::IterMut<'_, Element>: std::iter::Iterator` is not satisfied
  --> src/main.rs:11:22
   |
11 |         for entry in &self.elements.iter_mut() {
   |                      -^^^^^^^^^^^^^^^^^^^^^^^^
   |                      |
   |                      `&std::slice::IterMut<'_, Element>` is not an iterator; maybe try calling `.iter()` or a similar method
   |                      help: consider removing 1 leading `&`-references
   |
   = help: the trait `std::iter::Iterator` is not implemented for `&std::slice::IterMut<'_, Element>`
   = note: required by `std::iter::IntoIterator::into_iter`

I think this is because &self.elements is really a reference. Using self.elements would work, but I was hoping to modify the actual objects rather than a copy.

What would be a proper way of doing this?

like image 716
vise Avatar asked Jan 23 '15 20:01

vise


1 Answers

Switch to this:

for entry in self.elements.iter_mut() { /* ... */ }

Or more idiomatically:

for entry in &mut self.elements { /* ... */ }

IterMut contains a reference to the items in the vector (and thus will change the vector items directly), but it is itself an object on the stack that will be changed as the iteration progresses.

the trait bound `&std::slice::IterMut<'_, Element>: std::iter::Iterator` is not satisfied

This is saying that you've got an IterMut by reference. That is, the precedence is different from what you think it is:

&self.elements.iter_mut() 
&(self.elements.iter_mut()) // Is this
(&self.elements).iter_mut() // Not this

However, we'd have to do something like this:

(&mut self.elements).iter_mut()

because iter_mut needs a mutable reference as the receiver. Rust understands that and lets us just do the straightforward version and appropriately pass the mutability around:

self.elements.iter_mut()
like image 67
Shepmaster Avatar answered Sep 19 '22 00:09

Shepmaster