安全地搬出借来的内容

时间:2017-11-25 12:48:18

标签: rust borrow-checker

我有一个对结构的可变引用,我想通过传递一个函数来改变它的一个字段,并将结果设置为字段的新值。但是,我得到了一个"无法摆脱借来的内容"编译错误。

这是一个演示我的问题的简约示例:

struct InnerStruct {
    num: usize,
}

struct MyStruct {
    inner_struct: InnerStruct,
}

fn do_something(inner_struct: InnerStruct) -> InnerStruct {
    inner_struct
}

fn main() {
    let mut my_struct = MyStruct {
        inner_struct: InnerStruct { num: 0 },
    };

    let my_struct_ref = &mut my_struct;
    // This line compiles:
    // my_struct_ref.inner_struct = InnerStruct { num: 0 };
    my_struct_ref.inner_struct = do_something(my_struct_ref.inner_struct);
}

这是我得到的编译错误:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:21:47
   |
21 |     my_struct_ref.inner_struct = do_something(my_struct_ref.inner_struct);
   |                                               ^^^^^^^^^^^^^ cannot move out of borrowed content

函数do_something必须取得对内部结构的所有权才能执行其工作(在真实来源中,它在Tokio期货上运行)。

我有许多相同标题的帖子"无法摆脱借来的内容",所有这些内容的解决方案是克隆内容或传递引用而不是移动所有权,但我不能将这些解决方案应用于我的案例。

我无法理解Rust编译器在这种情况下试图防范的内容。我认为my_struct的每种可能性都保持一致。

成功编译此行:

my_struct_ref.inner_struct = InnerStruct { num: 0 };

以下三行也有效:

let inner_struct2 = InnerStruct { num: 0 };
let inner_struct = std::mem::replace(&mut my_struct_ref.inner_struct, inner_struct2);
my_struct_ref.inner_struct = do_something(inner_struct);

为什么这被认为是安全的,而第一个代码不是<?p?

我将很感激有关如何解决这个问题的任何想法,或者对我尝试做的事情的错误/不安全的解释。

1 个答案:

答案 0 :(得分:2)

如果do_something恐慌无法展开,则无法将my_struct_ref恢复为有效状态,但外部背景要求my_struct_ref有效。

如果有一种通用的方式说“如果这种恐慌只是崩溃而不是放松”,这将是很好的,这将使我的操作安全。

来自take crate的

take_mut提供了一个安全的包装器(它捕获了一个放松的恐慌并使其中止,解决了解除问题的方法)。