Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating through a Vec within a struct - cannot move out of borrowed content

Tags:

rust

I am writing a function for a struct which contains a Vec where I attempt to iterate through the Vec:

struct Object {
    pub v: Vec<f32>,
}

impl Object {
    pub fn sum(&self) -> f32 {
        let mut sum = 0.0;
        for e in self.v {
            sum += e;
        }
        sum
    }
}

However I get the following error:

error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:8:18
  |
8 |         for e in self.v {
  |                  ^^^^ cannot move out of borrowed content

My understanding is that since self is borrowed and that the for loop iteration is attempting to move the elements of v out into e.

From the error code, I read that a potential solution is to take ownership but I'm not quite certain how to do that.

I'm not trying to modify the vector or its elements. I just want to use the elements to run some computation.

like image 519
illeyezur Avatar asked Aug 05 '16 09:08

illeyezur


1 Answers

The line: for e in self.v is essentially saying for e in (*self).v; you're attempting to iterate over the vector by move, invoking its IntoIterator trait. This would destroy the vector completely, moving all the numbers out of it forever, which is not only not what you want, but also not allowed in this context because you're only allowed to read it.

You actually want to iterate over it by reference. There are two ways to do this:

for e in &self.v {
    // ...
}

This is essentially saying &((*self).v), since the . auto-dereferences you need to tell the compiler that you actually just want to borrow the vector.

or

for e in self.v.iter() {
    // ...
}

This may look funny because iter takes an &self. Why? Well, the compiler also auto-references if you call a function on a value that takes a reference. This is essentially (&((*self).v)).iter(), but that would suck to write so the compiler helps out.

So why doesn't it auto-reference in the for loop? Well, for x in self.v is a valid statement, and that may be what you intended to write. It's usually more important for the compiler to tell you that what you want want is impossible than assume you wanted something else. With the auto (de-)referencing above, no such ambiguity exists.

The former solution is preferred, but the latter is necessary if you want to use an iterator adapter.

Speaking of which, your sum already exists: just write self.v.iter().sum().

like image 80
Linear Avatar answered Oct 21 '22 17:10

Linear