簡體   English   中英

Rust 如何計算移動值的生命周期?

[英]How does Rust calculate lifetime of a moved value?

在Rust中,一個值的生命周期在scope的定義點和出點之間。

然而,out of scope 可能是竊取值的語句的結尾。

Rust 僅部分尊重這一點。 為什么?

舉個例子:

// This is the starting point, it compiles without errors/warnings, but does not do what it should.
struct Inner{x : i32}

struct Outer<'e>{
    s : &'e Inner,
    c : i32
}

fn print_inner_value(mut o : Outer) {
    println!("o.s.x = {:?}", o.s.x);
    o.c += 1;
}

fn change_inner(mut o : Outer) {
    let new_i = Inner{x : 40};
    o.c += 2;
    //o.s = &new_i;
    print_inner_value(o);
    println!("new_i.x = {:?}", new_i.x);
    //o.c += 3;
}

fn main () {
    let orinal_i = Inner {x : 10};
    let mut o = Outer{s : &orinal_i, c : 0};
    o.c += 4;
    change_inner(o);
}

我真正想要的是os = &new_i;這一行不予評論。

但如果我這樣做,我會得到 E0597 說 new_i 的壽命不夠長。

但它似乎活得足夠長,因為如果我改為取消注釋o.c += 3; 然后我得到 E0382 說 o.c 不能使用,因為它已被移動。

顯然在println.("new_i:x = {?,}". new_i;x); 行,價值new_i是活着的,價值o被移動到一個已經結束的 function 中,所以它不應該再活着。

所以問題是:為什么移動一個值會縮小它的 scope,但不會縮小它的生命周期?

您的錯誤是假設'e的生命周期代表Outer的生命周期:它不是。

相反,由於Outer<'e>類型的值o包含一個生命周期為'e的引用,因此該值o的生命周期必須短於(或等於) 'e —— 以免值o比所引用的生命周期長元素,並以懸空引用結束。


您遇到的真正問題是 function ( 'e ,此處)的生命周期參數由調用者確定,並在 function 本身內固定

當您在main中創建實例o時,計算的生命周期'eorinal_i的生命周期相匹配。

然后,在change_inner中,當您着手更改os時,類型系統要求您分配的任何引用的生命周期必須大於或等於這個預定'e ,即大於或等於orinal_i的生命周期。

包含所述引用的o將很快消失,這對所需的生命周期沒有影響。

通過查看 function 的非省略版本可以更好地觀察到這一點:

fn change_inner<'e>(mut o: Outer<'e>) {
    let new_i = Inner{x : 40};
    o.c += 2;
    //o.s = &new_i;
    print_inner_value(o);
    println!("new_i.x = {:?}", new_i.x);
    //o.c += 3;
}

上面的'e是 function之外的引用的生命周期,因此生命周期超過function。new_i 是在new_i中創建的變量,其生命周期比'e短,因此os不能綁定到&new_i

另一種理解方式是o的 scope 會影響orinal_i被借用多長時間,但不會影響orinal_i的生命周期:無論o的生命是短是長,都不會改變orinal_i的生命周期有多長, o訪問orinal_i的時間。


在您的特定情況下,存在一種解決方法:創建一個新的Outer值。

一個新值可以有一個新類型,其中'e參數不是固定的,編譯器將能夠在生命周期內推斷出一個新的“值”,一個比&new_i短的值:

fn change_inner<'e>(o: Outer<'e>) {
    let mut neo = o;

    let new_i = Inner{x : 40};
    neo.c += 2;
    neo.s = &new_i;

    print_inner_value(neo);

    println!("new_i.x = {:?}", new_i.x);
}

在這里,編譯器為neo'e選擇一個生命周期,它對os&new_i都有效——實際上是兩者中較短的一個。

請注意有相當多的魔法在起作用:

  • 您可能希望neo = o暗示neo具有與o完全相同的類型,但編譯器為neo'e推斷出不同的生命周期。 這是特定於生命周期的,其他通用參數將嚴格相等。 在這種情況下,您可以將neo = o視為neo = Outer { s: os, c: o.c }的簡寫。
  • 嚴格來說neonew_i ,所以你會期望&new_i不能分配給neo.s 然而,編譯器可以自由地將生命周期合並在一起,並且在這里這樣做,確定neonew_i彼此一樣長。

暫無
暫無

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

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