簡體   English   中英

在結構體的字段中使用引用時是否有任何限制?

[英]Are there any restrictions when using a reference in a field of a struct?

我試圖了解 Rust 中的生命周期如何影響結構。 附件是一個讓我困惑的最小例子。

我想給一個 struct 一個對象的引用,然后有必要更改這個對象。 由於借用時無法更改對象,因此我認為必須在更改時刪除引用。 所以我的想法是將變量定義為一個選項,並通過將其設置為None在修改對象期間刪除引用。 對於不使用 Struct 的示例,這似乎有效。 但是,如果我現在將此引用放入 Struct 中,則它不起作用。 在我看來,借用檢查器忽略了變量string不再被借用的事實。 有沒有辦法仍然使用結構實現所需的行為?

這有效( 鏈接到操場):

fn main() {
    let mut string = "mutable string".to_string();
    let mut ref_to_string: Option<&str> = Some(&string);
    ref_to_string = None;
    string = "mutated string".to_string();
    ref_to_string = Some(&string);
}

但是,這不起作用鏈接到操場

struct Foo<'a> {
    pub ref_data: Option<&'a str>,
}

fn main() {
    let mut string = "mutable string".to_string();
    let mut foo = Foo{ref_data: Some(&string)};
    foo.ref_data = None;
    string = "mutated string".to_string();
    foo.ref_data = Some(&string);
}

錯誤信息:

error[E0506]: cannot assign to `string` because it is borrowed
  --> src/main.rs:11:5
   |
9  |     let mut foo = Foo{ref_data: Some(&string)};
   |                                      ------- borrow of `string` occurs here
10 |     foo.ref_data = None;
11 |     string = "mutated string".to_string();
   |     ^^^^^^ assignment to borrowed `string` occurs here
12 |     foo.ref_data = Some(&string);
   |     ---------------------------- borrow later used here

For more information about this error, try `rustc --explain E0506`.

問題是您兩次引用string變量。 當借用第一個時,將&str生命周期綁定為至少作為foo活着。 引用位於“另一個”變量中的另一個字符串應該沒有問題:

fn main() {
    let string = "mutable string".to_string();
    let mut foo = Foo {
        ref_data: Some(&string),
    };
    foo.ref_data = None;

    let string = "mutated string".to_string();
    foo.ref_data = Some(&string);
}

操場

注意使用另一個let綁定而不是改變變量。

問題是整個Foo在一生中都是通用的。 這樣,當您分配foo = Foo {ref_data: Some(&string)}foo的類型是Foo<'lifetime_of_string> 您可以foo.ref_data地將foo.ref_data設置為None ,但就借用檢查而言,仍然有一個存活對象的生命周期與string的生命周期重疊。 出於這個原因,只要foo存在, string就會被借用。 唯一的方法是刪除整個foo

let mut string = "mutable string".to_string();
let mut foo = Foo{ref_data: Some(&string)};
drop(foo);
foo = Foo { ref_data: None };
string = "mutated string".to_string();
foo.ref_data = Some(&string);

秘密在於Foo結構體的定義:

struct Foo<'a> {
    pub ref_data: Option<&'a str>,
}

更具體地說,在'a生命周期說明符”中。 通過指定Foo存在於'a並且ref_data具有相同的生命周期( &'a str ),你說你的&str將與Foo一樣長。 所以只要Foo還活着,編譯器就不能刪除對string的引用。

不幸的是,只有在字段為Some時,才能指定結構體的生命周期為'a

要改變結構引用的對象,您可以:

  1. 將對象的所有權轉移到結構體,然后從結構體中獲取對它的可變引用。
  2. 使用內部可變性(參見RefCell )。
  3. 在變異之前刪除你的結構,並在變異完成后重新創建它。

哪種方法更好取決於您的特定用例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM