使用结构本身的值更新结构给出:"cannot borrow `*self` as mutable because it is also borrowed as immutable"

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

我正在尝试创建一个 struct,它通过附加一些“常量”字符串 first_step 来修改其 current_value,该字符串是在首次创建 struct 时定义的。

代码

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

我认为错误很明显(self.add 中的 self 被借用为可变的,因为 add 的签名具有 &mut self,但随后的值be appended 也来自self,但是这次是作为不可变借来的,我们不能借用self既可变又不可变。

但我不知道如何解决这个问题,创建一个可以使用在创建结构本身时定义的一些“常量”值来更新自身的数据结构。在实际的“现实生活”案例中,我有一个包含 filefile_header: Stringstruct,并且我想要一个将 file_header 写入 file.

Rust 确实 允许单独借用 struct 部分 ,但是当您调用 function/method它采用 &mut Self,它总是借用整个 struct — 函数体从不用作附加信息。因此,对于您想使用来自另一部分的信息来改变结构的一部分等问题的解决方案是重写您的函数签名,以便它 具有必要的信息。

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);
    }

}

你的描述“......一个可以用一些在创建结构本身时定义的“常量”值更新自己的数据结构......”表明你可能遇到比这个简单示例更复杂的情况。如果你有多个需要更新的可变字段(或者即使你真的想使用方法语法),你可以创建另一个 struct 包含正确的字段子集——然后像 do_something 这样的方法可以在内部结构上调用普通 &mut self 方法。

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);
    }
}