我正在尝试开发一个 Rust 应用程序。由于对 Rust 相当陌生,我发现借用检查器很难使用。下面是我从更大的代码库中分离出来的 MRE,但它具体说明了我的问题。在
do_something
内,该行被注释掉(标记为 2)),程序可以正常编译并按预期工作,但是当该行被注释掉(标记为 1))时,它会失败,并显示错误消息。
我意识到问题是由于内存安全造成的,并且编译器试图确保没有任何内容会意外改变......但是我无法理解第 1) 行和第 2) 行之间确切的根本区别是什么;据我所知,它们是相同的。
我也一直在拼命寻找一种通用的方法来解决问题。我之前在同一个代码库中用几个
clone
解决了一个非常相似的问题。在这种情况下,克隆 v(我怀疑这是问题的根源?)并不能解决问题。
#[derive(Debug, Default)]
struct MyStruct {
my_idx: usize,
my_vals: Vec<String>,
my_log: Vec<String>,
}
impl MyStruct {
pub fn new() -> Self { Self::default() }
// Push a message to the log-vector.
pub fn push_msg(&mut self, msg: String) {
let tmp = self.fmt_msg(msg);
self.my_log.push(tmp);
}
// Format a message and return a String
pub fn fmt_msg(&self, msg: String) -> String { format!("msg is: {}", msg) }
// Get a value from my_vals. Create a log message, two ways.
pub fn do_something(&mut self) -> String {
let ret_val = match self.my_vals.get(self.my_idx) {
Some(v) => {
let msg = self.fmt_msg(format!("Some {}", v));
self.push_msg(msg); // 1) This line doesn't work
// self.my_log.push(msg); // 2) This line works
format!("Some {:?}", v)
},
None => format!("None")
};
ret_val
}
}
fn main() {
let mut ms = MyStruct::new(); // Init struct
ms.my_vals.push(String::from("aa")); // Push some value to the struct
ms.push_msg(String::from("bcd")); // Test push_msg-function, works as a stand-alone call
ms.do_something(); // Test function
println!("Main, after: {:?}", ms); // Just check the state of the struct after
}
在MRE中使用1)时出现如下错误信息:
PS C:\Users\rust_stuff\borrow_test> cargo run
Compiling borrow_test v0.1.0 (C:\Users\rust_stuff\borrow_test)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src\main.rs:24:17
|
21 | let ret_val = match self.my_vals.get(self.my_idx) {
| ------------ immutable borrow occurs here
...
24 | self.push_msg(msg); // 1) This line doesn't work
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
25 | // self.my_log.push(msg); // 2) This line works
26 | format!("Some {:?}", v)
| - immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `borrow_test` (bin "borrow_test") due to previous error
Stack Overflow 上已经有几个非常相似的问题了,但我还没有设法将这些答案转换为我的具体案例。在其他答案中,我发现这个问题最相似。
错误信息显示,从
match
语句开始,v
中获取的Some(v)
引用仍然在使用,直到这个match
臂结束(产生返回值),而变异操作.push_msg()
借用了self
作为一个整体。
但v
指的是self
的一部分;借用检查器禁止这种情况。
一种解决方法是在变异操作.push_msg()
之前
准备结果,以便在此变异之后不再使用参考
v
。
pub fn do_something(&mut self) -> String {
let ret_val = match self.my_vals.get(self.my_idx) {
Some(v) => {
let result = format!("Some {:?}", v);
let msg = self.fmt_msg(format!("Some {}", v));
self.push_msg(msg);
result
}
None => format!("None"),
};
ret_val
}