为什么我会得到“寿命不足”的返回值?

时间:2018-12-03 01:27:09

标签: rust language-lawyer

在检查How do I box Arc and Mutexed variables?时,我遇到一个问题,即看起来不错的代码在从Mutex构造返回值时会生成“寿命不足”错误。只需将lock().unwrap()访问权限从返回对象中移出即可消除该错误-但我想了解为什么Rust在这种情况下会抱怨生命周期问题。

我能够将代码简化为一个非常简单的复制器:第一个函数编译正常,第二个函数生成错误消息,并且它们几乎相同。

use std::sync::Mutex;

pub struct Response {
    resp: String,
}

pub fn get() -> Response {
    let body = Mutex::new("a".to_string());
    let x: std::sync::MutexGuard<_> = body.lock().unwrap();
    Response { resp: x.clone() }
}

pub fn get2() -> Response {
    let body = Mutex::new("a".to_string());
    Response {
        resp: body.lock().unwrap().clone(),
    }
}
error[E0597]: `body` does not live long enough
  --> src/lib.rs:16:15
   |
16 |         resp: body.lock().unwrap().clone(),
   |               ^^^^ borrowed value does not live long enough
17 |     }
18 | }
   | - `body` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

2 个答案:

答案 0 :(得分:2)

正如Stargateur的回答所指出的,其原因是临时人员的一生。尽管Rust还没有完整的规范,但语言参考仍然相当不错,至少可以提示您了解其行为。这是section about temporary lifetimes的相关部分:

  

[T]临时值的生存期通常为

     
      
  • 最里面的语句;块的尾部表达式被视为包围该块的语句的一部分,或者
  •   
  • 如果在if的条件表达式中或while表达式的循环条件表达式中创建了临时变量,则条件表达式或循环条件表达式。
  •   

函数第二个版本中body.lock().unwrap()的最里面的语句是return表达式。上面的规范指出,此表达式是“包含该语句的语句的考虑部分”,在这种情况下实际上并不存在,但仍给出了正确的主意:删除函数体本地的所有变量在返回表达式中的任何临时对象之前被删除,因此body在借用body的MutexGuard之前被删除。您发现的修复程序可确保将临时变量在body之前删除,因为局部变量的删除顺序大致与创建时相反。

答案 1 :(得分:1)

使用#![feature(nll)]会给出一个精确的错误:

   |
19 |         resp: body.lock().unwrap().clone(),
   |               ^^^^----------------
   |               |
   |               borrowed value does not live long enough
   |               a temporary with access to the borrow is created here ...
20 |     }
21 | }
   | -
   | |
   | `body` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop`
   | code for type `std::sync::MutexGuard`
   |
   = note: The temporary is part of an expression at the end of a block. Consider forcing
   this temporary to be dropped sooner, before the block's local variables are dropped.
   For example, you could save the expression's value in a new local variable `x` and then make
   `x` be the expression at the end of the block.

相当长的顺便说一句;)这是因为临时物是放在身体后的,您也可以这样做:

pub fn get3() -> Response {
    let body = Mutex::new("a".to_string());
    let resp = body.lock().unwrap().clone();
    Response {
        resp,
    }
}