了解一生的问题

Understanding a lifetime issue

我在编译为 Firecracker 所做的更改时遇到了生命周期错误(在 aarch64 上,但我怀疑该问题是否与架构相关):

error[E0716]: temporary value dropped while borrowed
   --> src/vmm/src/device_manager/mmio.rs:174:24
    |
174 |           let int_evt = &serial
    |  ________________________^
175 | |             .lock()
176 | |             .expect("Poisoned legacy serial lock")
    | |__________________________________________________^ creates a temporary which is freed while still in use
177 |               .interrupt_evt();
    |                               - temporary value is freed at the end of this statement
178 |           vm.register_irqfd(int_evt, self.irq)
    |                             ------- borrow later used here
    |
    = note: consider using a `let` binding to create a longer lived value

原始代码(编译良好)是:

vm.register_irqfd(&serial
        .lock()
        .expect("Poisoned legacy serial lock")
        .interrupt_evt(), self.irq)
    .map_err(Error::RegisterIrqFd)?;

我不明白其中的区别。错误消息似乎表明 expect() 正在返回一个临时文件并且我正在对它进行 const 引用,在 C++ 中这会延长临时文件的生命周期,不是在 Rust 中吗?无论哪种方式,为什么它在原始代码中有效,但在我绑定到左值后却无效(C++ 的说法,我不确定它是否与 Rust 相同)?

我尝试在此处创建 SSCE,但它按预期工作!

一个简单的、可重现的问题示例 (playground):

// create array inside mutex
let mutex = Mutex::new([ 0i32 ]);

// get reference to item inside array
let item: &i32 = mutex.lock().unwrap().get(0).unwrap();

// use reference for something
println!("item = {:?}", item);

mutex.lock().unwrap()returnsaMutexGuard<'_, Option<i32>>,就是借用互斥锁里面的数据。它还拥有对数据的锁定,当保护被删除时释放,这意味着没有其他人可以同时借用数据。

当你在那个守卫上调用一个内部类型的方法时(比如上面例子中的.get,或者你代码中的.interrupt_evt),它将借用守卫的生命周期,因为你只能在守卫存在的情况下安全地访问数据。但是守卫没有存储在任何变量中,所以它只是暂时存在于该语句中,并在它结束时立即被删除。所以你不能得到语句外数据的引用。

解决这个问题很简单:先把守卫存到一个变量里,然后再借用它。这将确保守卫的寿命比您从中获得的参考更长(playground):

// create array inside mutex
let mutex = Mutex::new([ 0i32 ]);

// get reference to item inside array
let guard = mutex.lock().unwrap();
let item: &i32 = guard.get(0).unwrap();

// use reference for something
println!("item = {:?}", item);

// guard is now destroyed at end of scope
// and mutex lock is released here