2017-11-25 127 views
0

我對結構有一個可變引用,我想通過傳遞一個函數來更改它的一個字段,並將結果設置爲該字段的新值。但是,我收到「無法移出借來的內容」編譯錯誤。安全地移出借用內容

這是證明我的問題,一個簡約的例子:

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

如何走到這被認爲是安全的,而第一個代碼是不是?

我將不勝感激關於如何解決這個問題,或解釋什麼是錯誤的/不安全的,我想要做的。

回答

2

如果do_something panics展開是不可能的 - 您不能將my_struct_ref恢復到有效狀態,但外部環境要求my_struct_ref有效。

如果有一種通用的方式說「如果這種恐慌只是崩潰而不是放鬆」,這將是很好的,這將使這種操作安全,據我所知。

take from take_mut crate提供了一個安全的包裝(它捕捉一個放鬆的恐慌,並使其中止,解決問題與解繞)。

+0

我認爲恐慌是一種崩潰。恐慌之後有可能恢復嗎? – real

+1

我認爲['catch_unwind']的文檔(https://doc.rust-lang.org/stable/std/panic/fn.catch_unwind.html)可以很好地解釋它 - 「這個函數只捕獲展開的恐慌,而不是那些放棄這個過程的人。「 – Stefan