Understand error E0500

Hi everyone,

I came across the capture modes of the Closure types in the Rust Reference and I took the example from the docs, changed the commented lines a bit, and used it in a simple example to better understand what's going on.

use  std::collections::HashSet;

#[derive(Debug)]
struct SetVec {
    set: HashSet<u32>,
    vec: Vec<u32>
}

impl SetVec {
    fn populate(&mut self) {
        // let vec = &mut self.vec;
        self.set.iter().for_each(|&n| {
            self.vec.push(n);   // use `vec` to compile successfully
        })
    }
}

// My code example
fn main() {
	let mut set_vec = SetVec {
		set: [1,2,3].iter().cloned().collect(),
		vec: vec![]
	};

	set_vec.populate();
	
    println!("set_vec = {:?}", set_vec);
}

(Playground)

The code above does not compile because I use self inside the closure as in self.vec.push(n). This tells the closure that it should fully capture self.

The way I understand it is that the Rust compiler is complaining about this situation:

  • self.set is an immutable shared-borrow : read-only (because of the iterator)
  • self is a mutable borrow : exclusive to closure (because of the self.vec.push(n))

Is my understanding correct ?

Thank you!

You are taking a mutable reference to self to create an iterator, and then using a mutable reference to self inside the iterator to populate the field 'vec'. If you split the sequence of operations so you are only mutating self one filed at a time, it will pass the compiler. Others may be able to offer a more idiomatic approach.

impl SetVec {
    fn populate(&mut self) {
        let mut vec = Vec::new();
        self.set.iter().for_each(|&n| {
            vec.push(n);   // use `vec` to compile successfully
        });
        self.vec = vec;
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c362b3475a8c448dceabebff1bbe25d9

1 Like

Note that in the upcoming (soon!) Rust 2021 edition, the original code will work, due to the new "Disjoint captures in closures" feature.

3 Likes

As can already be demonstrated in the playground. (Edition selection can be found under the “advanced compilation options”, i.e. the three dots to the right of Stable/Beta/Nightly selection.) By the way, just 4 more days until it’s on stable :partying_face:

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.