简体   繁体   中英

update struct using a value from the struct itself gives: "cannot borrow `*self` as mutable because it is also borrowed as immutable"

I am trying to create a struct that modifies its current_value by appending some "constant" string first_step which is defined when the struct is first created.

code

fn main() {
    let mut adder = Adder {
        current_value: "init".to_string(),
        first_step: ", first".to_string(),
    };
    adder.do_something()
}

struct Adder {
    current_value: String,
    first_step: String,
}

impl Adder {
    fn add(&mut self, value: &String) {
        self.current_value = format!("{}{}", self.current_value, value);
    }

    fn do_something(&mut self) {
        // cannot borrow `*self` as mutable because it is also borrowed as immutable
        // mutable borrow occurs here rustc(E0502)
        // main.rs(24, 18): immutable borrow occurs here
        // main.rs(24, 14): immutable borrow later used by call
        self.add(&self.first_step);
    }
}

playground

I think the errors are quite clear (the self in self.add is borrowed as mutable because the signature of add has &mut self , but then the value to be appended also comes from self , but this time borrowed as immutable, and we cannot borrow self both mutable and immutable).

But I don't know how to fix this, creating a data structure that can update itself with some "constant" values that are defined when the structure itself is created. In the actual "real life" case I have a struct that contains both a file and file_header: String , and I want to have a method that writes the file_header into the file .

Rust does allow for borrowing parts of a struct separately, but when you call a function/method that takes &mut Self , that always borrows the entire struct — the body of the function is never used as additional information. So, a solution to problems like where you want to mutate part of your structure using information from another part is to rewrite your function signature so that it does have the necessary information.

impl Adder {
    /// Algorithm implementation; takes all components explicitly.
    /// Is not a method.
    fn add_impl(current_value: &mut String, add_value: &str) {
        current_value.push_str(add_value);
    }

    /// Method for external use — less flexible, but simple.
    pub fn add(&mut self, value: &str) {
        Self::add_impl(&mut self.current_value, value);
    }

    fn do_something(&mut self) {
        Self::add_impl(&mut self.current_value, &self.first_step);
    }

}

Your description “…a data structure that can update itself with some "constant" values that are defined when the structure itself is created…” suggests that you might have a more complicated situation than this simple example. If you have more than one mutable field that needs updating (or even if you really want to use method syntax), you can make another struct that contains the right subset of fields — then the methods like do_something can call ordinary &mut self methods on the inner struct.

struct FancyAdder {
    first_step: String,
    data: AdderData,
}

struct AdderData {
    current_value: String,
    ...
}

impl FancyAdder {
    fn do_something(&mut self) {
       // This borrows `self.data` mutably and `self.first_step` immutably.
       // No overlap.
       self.data.add(&self.first_step);
    }
}

impl AdderData {
    fn add(&mut self, value: &str) {
        self.current_value.push_str(value);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM