Mutation of one field when repeating another immutable field

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 compilations are performed:

example.rs:15:26: 15:30 error: cannot borrow `*self` as mutable because it is also borrowed as immutable [E0502]
example.rs:15                 "foo" => self.append("it was foo\n"),
                                       ^~~~
example.rs:13:21: 13:25 note: previous borrow of `*self` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `*self` until the borrow ends
example.rs:13         for item in self.data().items.iter() {
                                  ^~~~
example.rs:19:10: 19:10 note: previous borrow ends here
example.rs:13         for item in self.data().items.iter() {
              ...
example.rs:19         }
                      ^
example.rs:16:22: 16:26 error: cannot borrow `*self` as mutable because it is also borrowed as immutable [E0502]
example.rs:16                 _ => self.append("it was something else\n"),
                                   ^~~~
example.rs:13:21: 13:25 note: previous borrow of `*self` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `*self` until the borrow ends
example.rs:13         for item in self.data().items.iter() {
                                  ^~~~
example.rs:19:10: 19:10 note: previous borrow ends here
example.rs:13         for item in self.data().items.iter() {
              ...
example.rs:19         }
                      ^
error: aborting due to 2 previous errors

What is the proper way to structure your code so that you can change a variable field outputduring iteration over an immutable field data? Assume that indirect attribute binding is Generatorused to share similar logic with other structures, so access to fields MyStructfrom the default method implementations of the method should be done using access methods such as this.

+4
source share
3 answers

, Generator , MyStruct , .

.


, ; , .

, , :

  • , - ,
  • ,

... .

, , !


, ?

:

  • ( , )
  • "" append, .
  • ...
+4

Rust; .

fn generate_items(&mut self) {
    // Take the data. The borrow on self ends after this statement.
    let data = std::mem::replace(self.data(), Data { vec![] });
    // Iterate over the local version. Now append can borrow all it wants.
    for item in data.items.iter() {
        match *item {
            "foo" => self.append("it was foo\n"),
            _ => self.append("it was something else\n"),

        }
    }
    // Put the data back where it belongs.
    std::mem::replace(self.data(), data);
}

, , . , output() , data(), , , . , , . , , , .

, ; .

+6

RefCell:

RefCell Rust " ", , , , . Borrows RefCells " ", Rust, , . RefCell , ; , .

use std::cell::RefMut;
use std::cell::RefCell;

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

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

    fn data(&self) -> &Data;

    fn generate_items(&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(&self) -> RefMut<String>;
}

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

}

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

        self.output.into_inner()
    }

}

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

    fn output(&self) -> RefMut<String> {
        self.output.borrow_mut()
    }
}

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

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

    let output = generator.generate();

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

+3

All Articles