借用具有字段的可变结构体

3
我将尽力为您翻译以下内容,涉及编程相关内容:

我正在尝试在函数调用中可变地借用一个结构体及其某些成员。由于第一个结构体的可变借用,任何后续的(成员)借用都会标记错误second mutable borrow occurs here

情景很简单,我们有一个保存状态的结构体:

struct State {
    a: i32,
    b: i32,
    result_add: i32,
    result_subtract: i32
}

并且需要一个函数,根据传递的成员(在我们的情况下为ab),填充结构中result_addresult_subtract的计算结果。

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

有点勉强的例子,但是想法是var1var2也可以是其他结构成员。现在我们调用:

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)
这样做可以起作用,但对于更复杂和奇怪的内容来说很繁琐。是否有其他方法在可变方式下借用结构体及其成员?
游乐场:原始 提到的解决方案

1
这个回答解决了你的问题吗?为什么通过提取方法进行重构会触发借用检查器错误? - Stargateur
2个回答

2
这违反了 Rust 和借用的基本规则之一,即你可以拥有一个可变引用或多个不可变引用 - 但二者不能混合使用。

我猜编译器看到我们多次借用结构体并停止了这个过程,但是如果整个结构体是可变的,这应该没问题,对吧?

如果我将整个结构体作为可变借用,Rust 编译器会确保没有其他引用,无论是可变的还是不可变的。这就是 Rust 和其内存安全性的工作方式。
你可以使用许多不同的方法来构造此代码以确保只存在一个可变引用 - 你已经利用了 分割借用,也许可以进一步将结构体拆分成两个较小的结构体?
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);
}

Playground Link


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

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接