安全地搬出借来的内容

moving out of borrowed content safely

我有一个对结构的可变引用,我想通过函数传递它来更改其中一个字段,并将结果设置为该字段的新值。但是,我收到 "cannot move out of borrowed content" 编译错误。

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

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 futures 上运行)。

我有很多标题相同的帖子 "cannot move out of borrowed content",所有这些帖子的解决方案是克隆某些内容或传递引用而不是移动所有权,但我无法将这些解决方案应用于我的案例.

我不明白 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);

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

如果有任何关于如何解决这个问题的想法,或者关于什么是 wrong/unsafe 我正在尝试做的事情的解释,我将不胜感激。

如果 do_something 恐慌解除是不可能的 - 您无法将 my_struct_ref 恢复到有效状态,但外部上下文需要 my_struct_ref 有效。

如果有一种通用的说法 "if this panics just crash instead of unwind" 就好了,据我所知这将使此类操作安全。

take from the take_mut crate 提供了一个安全的包装器(它捕获了一个展开的恐慌并让它中止,解决了展开的问题)。