为什么这个值活得不够长?

Why does this value not live long enough?

我不明白为什么我会从这段代码中得到以下编译器错误:

struct Superhero<'a> { name: &'a String, power: &'a i32 } //  1    
                                                          //  2    
fn main() {                                               //  3    
    let n = "Bruce Wayne".to_string();                    //  4    
    let r;                                                //  5    
    {                                                     //  6    
        let p = 98;                                       //  7    
        {                                                 //  8    
            let hero = Superhero{ name: &n, power: &p };  //  9    
            r = hero.name;                                // 10    
        }                                                 // 11    
        println!("{}", r);                                // 12    
    }                                                     // 13    
}                                                         // 14    

编译器错误:rustc 1.27.1 (5f2b325f6 2018-07-07)

error[E0597]: `p` does not live long enough
  --> src/main.rs:9:53
   |
9  |             let hero = Superhero{ name: &n, power: &p };
   |                                                     ^ borrowed value does not live long enough
...
13 |     }
   |     - `p` dropped here while still borrowed
14 | }
   | - borrowed value needs to live until here

以下是我认为这段代码会逐行执行的操作。其中一行或多行有问题,因为此代码无法编译。

 4: Initialize name: String to "Bruce Wayne".to_string();
 5: Declare r to be initialized in a different scope
 6: Begin a new scope (A)
 7: Initialize p to 98
 8: Begin a new scope (B)
 9: Initialize hero: Superhero to a new struct
       hero.name refers to the variable{n},
       hero.power refers to the variable{p}  
10: Copy a reference to the variable{n}, 
       since reference types are copy, both hero.name and r are distinct references to the variable{n}.
11: End scope (B): hero and the two references it owns {hero.name, hero.power} are dropped.
12: Print the value of the variable{r}: Should print "Bruce Wayne"
13: End scope (A): the variable{p} is dropped.
14: End scope for main. The variables {n, r} are dropped.

为什么编译器错误说第13行仍然在借用p?不应该在第 11 行删除 hero(以及随后的 hero.power)吗?此时应该没有任何内容涉及 p

奇怪的是,更改值(pr)的初始化顺序解决了这个问题,我不知道为什么。

修复方法:

  1. 将第 7 行 let p = 90; 移动到第 4 行和第 5 行之间
  2. 将第 5 行 let r; 移动到第 7 行和第 8 行之间

在这两种情况下,只需在 p 之后声明 r 即可确保在删除时没有任何内容仍然是 "borrowing" p。这对我来说毫无意义,因为我觉得 rp 或任何可能借用 p 的东西完全没有关系。

此代码runs with non-lexical lifetimes enabled.

什么 属性 词法生命周期导致无法编译,非词法生命周期如何解决这个问题?

https://play.rust-lang.org/?gist=48362cfc5ee81ff07628f9b60477c4cb&version=nightly&mode=debug&edition=2015

这是另一种修复方法。结构中 'power' 和 'name' 的生命周期相同 (&'a)。所以当 'power' 超出范围时,编译器会认为 'name' 也超出范围。所以你需要为你的结构定义另一个生命周期

这只是一个猜测,但这是我认为会发生的情况:

  • 当您声明 Superhero 时,您声明 namepower 应该具有相同的生命周期。
  • r 的类型被推断为 &String(或者可能是 &str,关键是 r 是一个引用)。对于词法生命周期,r 必须一直存在到声明它的块的末尾,因此直到第 14 行。
  • 因为你影响 hero.namerhero.name 应该至少和 r 一样长,因此 hero.name 应该活到第 14 行。
  • 由于 hero.namehero.power 根据结构声明应该具有相同的生命周期,因此 hero.power 也应该存在到第 14 行。
  • 由于 hero.power 借用 pp 应该存活到第 14 行,但它只存活到声明它的块的末尾(第 13 行)。

它使用非词法生命周期的原因是因为编译器注意到您在第 12 行之后没有使用 r,因此能够相应地缩短生命周期。请注意 it doesn't work even with nll if you use r after the closing brace of line 13.