【问题标题】:Borrowing mutable struct with fields借用带字段的可变结构
【发布时间】:2020-06-06 12:45:31
【问题描述】:

我试图在函数调用中可变地借用一个结构及其一些成员。看到结构的第一个可变借用,任何后续借用(成员的)都标记为错误second mutable borrow occurs here

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

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

还有一个函数,根据传递的成员(在我们的例子中为a和b)填充结构中result_add和result_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;
}

有点人为的例子,但想法是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)

这可行,但对于更复杂且非常奇怪的事情来说很麻烦。除了以可变方式借用整个结构同时还借用其成员之外,还有其他方法吗?

游乐场:OriginalMentioned solution

【问题讨论】:

标签: rust


【解决方案1】:

这违反了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);
}

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-22
      • 1970-01-01
      • 1970-01-01
      • 2022-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多