如何在不分配新盒子的情况下转换盒装参考的生命周期?

How to convert lifetime of boxed reference without allocating a new box?

上下文

Playground,有效:

fn get_owned_box_working<'a>(b: Box<&'a i32>) -> Box<&'static i32> {
    Box::new(&42)
}

但这不是:

fn get_owned_box_broken<'a>(b: Box<&'a i32>) -> Box<&'static i32> {
    *b = &42;
    b
}
error[E0308]: mismatched types
 --> src/lib.rs:3:5
  |
3 |     b
  |     ^ lifetime mismatch
  |
  = note: expected struct `Box<&'static i32>`
             found struct `Box<&'a i32>`
note: the lifetime `'a` as defined here...
 --> src/lib.rs:1:25
  |
1 | fn get_owned_box_broken<'a>(b: Box<&'a i32>) -> Box<&'static i32> {
  |                         ^^
  = note: ...does not necessarily outlive the static lifetime

问题

How come the compiler can't update the lifetime of the existing box from 'a -> 'static when I mutate it?

从编译器的角度来看,您无法将使用 'a 的值“更新”为使用 'static。您正在分配给它,但类型保持不变。然后稍后您尝试从 Box<&'a i32> 转换为 Box<&'static i32>,并且它正确地保释。

Is there some way to get this to work without the extra allocation from creating a new box?

是,但仅使用 unsafePlayground

fn get_owned_box_broken<'a>(s: Box<&'a i32>) -> Box<&'static i32> {
    unsafe {
        let s = Box::into_raw(s);
        let s = s.cast::<&'static i32>();
        s.write(&42);
        Box::from_raw(s)
    }
}

但是,如果您需要,请仔细考虑:您可能负担得起分配。

你不能那样做,因为生命周期是类型的一部分。

因此,当您分配 *b = &42; 时,您的左侧部分的类型为 &'a i32,右侧部分的类型为 &'static i32。可以将更大的生命周期强制为更小的生命周期,所以没关系。但是你的变量 b 仍然有生命周期参数 'a 的类型,它在赋值后没有改变。

当您从函数 return b 时,您尝试将 Box<&'a i32> 转换为 Box<&'static i32>。由于 'static 大于 'a,因此失败。