Mutating one field while iterating over another immutable field

Viewed 1452

Given the following program:

struct Data {
    pub items: Vec<&'static str>,
}

trait Generator {
    fn append(&mut self, s: &str) {
        self.output().push_str(s);
    }

    fn data(&self) -> &Data;

    fn generate_items(&mut self) {
        for item in self.data().items.iter() {
            match *item {
                "foo" => self.append("it was foo\n"),
                _ => self.append("it was something else\n"),
            }
        }
    }

    fn output(&mut self) -> &mut String;
}

struct MyGenerator<'a> {
    data: &'a Data,
    output: String,
}

impl<'a> MyGenerator<'a> {
    fn generate(mut self) -> String {
        self.generate_items();

        self.output
    }
}

impl<'a> Generator for MyGenerator<'a> {
    fn data(&self) -> &Data {
        self.data
    }

    fn output(&mut self) -> &mut String {
        &mut self.output
    }
}

fn main() {
    let data = Data {
        items: vec!["foo", "bar", "baz"],
    };

    let generator = MyGenerator {
        data: &data,
        output: String::new(),
    };

    let output = generator.generate();

    println!("{}", output);
}

The following errors are produced trying to compile it:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:15:26
   |
13 |         for item in self.data().items.iter() {
   |                     ----                   - immutable borrow ends here
   |                     |
   |                     immutable borrow occurs here
14 |             match *item {
15 |                 "foo" => self.append("it was foo\n"),
   |                          ^^^^ mutable borrow occurs here

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:16:22
   |
13 |         for item in self.data().items.iter() {
   |                     ----                   - immutable borrow ends here
   |                     |
   |                     immutable borrow occurs here
...
16 |                 _ => self.append("it was something else\n"),
   |                      ^^^^ mutable borrow occurs here

What is the proper way to structure the code so that the mutable field output can be written to while iterating over the immutable field data? Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.

3 Answers
Related