我正在尝试在函数调用中可变地借用结构及其某些成员。看到结构的第一个可变借用,(成员的)任何后续借用都标记有错误second mutable borrow occurs here
场景很简单,我们有一个保存状态的结构:
struct State {
a: i32,
b: i32,
result_add: i32,
result_subtract: i32
}
还有一个函数,该函数根据传递的成员(在我们的示例中为result_add
和result_subtract
)填充结构中a
和b
的计算结果
fn do_calc(state : & mut State, var1 : &mut i32, var2: &mut i32) {
*var1 = 4;
*var2 = 2;
state.result_add = state.a + state.b;
state.result_subtract = state.a - state.b;
}
有些人为的例子,但是想法是var1
和var2
也可以是其他结构成员。现在我们调用:
do_calc(&mut state, &mut state.a, &mut state.b);
并得到错误:
error[E0499]: cannot borrow `state.a` as mutable more than once at a time
--> src/main.rs:24:25
|
24 | do_calc(&mut state, &mut state.a, &mut state.b);
| ------- ---------- ^^^^^^^^^^^^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call
我猜编译器会看到我们多次借用该结构并停止了此操作,但是如果该结构作为一个整体是可变的,那岂不是可以吗?
一种解决方案是删除结构引用并借用每个需要突变的字段:
fn do_calc(result_add : &mut i32, result_subtract : &mut i32, var1 : &mut i32, var2: &mut i32)
这可以工作,但是对于更复杂和非常奇怪的事情却很麻烦。除了以可变的方式整体借用该结构同时还借用其成员之外,还有其他选择吗?
答案 0 :(得分:0)
这违反了Rust and borrowing的一项基本规则,即您可以拥有一个可变引用或许多不可变引用,但不能同时使用两者。
我想编译器会看到我们多次借用该结构并停止了此操作,但是如果该结构作为一个整体是可变的,那还行吗?
如果我将整个结构借为可变的,Rust编译器将确保没有其他引用,可变的或不可变的。这就是Rust及其内存安全性的工作方式。
您可以采用多种不同的方法来构造此代码,以确保只有一个可变的引用-您已经利用了split borrowing,也许您可以进一步使用它并将您的结构分解为两个较小的结构结构?
struct Input {
a: i32,
b: i32,
}
struct Output {
add: i32,
subtract: i32,
}
struct State {
input: Input,
result: Result,
}
fn do_calc(input: &mut Input, result: &mut Output) {
input.a = 4;
input.b = 2;
result.add = input.a + input.b;
result.subtract = input.a - input.b;
}
fn main() {
let mut state = State {
input: Input { a: 0, b: 0 },
result: Output {
add: 0,
subtract: 0,
},
};
do_calc(&mut state.input, &mut state.result);
println!("result_add {} ", state.result.add);
println!("result_subtract {} ", state.result.subtract);
}
答案 1 :(得分:-2)
也许您的do_calc
对一个电话负有太多责任。您可以拆分它。
Playground
struct State {
a: i32,
b: i32,
result_add: i32,
result_subtract: i32
}
fn do_calc(var1: &mut i32, var2: &mut i32) {
*var1 = 4;
*var2 = 3;
}
fn finish_calc(state: &mut State){
state.result_add = state.a + state.b;
state.result_subtract = state.a - state.b;
}
fn main() {
let mut state = State { a:0, b:1, result_add:2, result_subtract:3 };
{
do_calc(&mut state.a, &mut state.b);
finish_calc(&mut state);
}
}