为什么这个值寿命不长?

时间:2018-07-12 00:30:07

标签: rust lifetime lexical-scope borrowing

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

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行仍在借用phero(以及随后的hero.power)是否应该放在第11行上?此时,应该没有任何内容引用p

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

解决方法:

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

在这两种情况下,只要在r之后声明p,就可以确保在丢弃p时,什么也不会“借用”。这对我完全没有意义,因为我觉得rp或可能借用p的任何东西都没有任何关系。

此代码runs with non-lexical lifetimes enabled

词汇生存期的哪些属性导致其无法编译,而非词汇生存期如何解决此问题?

2 个答案:

答案 0 :(得分:3)

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

  • 声明Superhero时,表示namepower的生存期应相同。
  • r的类型被推断为&String(或者也许是&str,关键是r是引用)。在词法生存期中,r必须生存到声明它的块的末尾,直到第14行。
  • 由于您影响hero.namer,因此hero.name的生存期至少应与r一样长,因此hero.name的生存期应到第14行。 li>
  • 由于hero.namehero.power在每个结构声明中应具有相同的生存期,因此hero.power也应保留到第14行。
  • 由于hero.power借用了p,因此p的使用期限应一直到第14行,但它只存在直到声明它的块的末尾(第13行)。

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

答案 1 :(得分:1)

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

这是另一种解决方法。结构中'power'和'name'的生存期相同(&'a)。因此,当“电源”超出范围时,编译器会认为“名称”也超出范围。因此,您需要为您的结构定义另一个生存期