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

Advertisements

Context

Playground, This works:

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

but this doesn’t:

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

Question

  • How come the compiler can’t update the lifetime of the existing box from 'a -> 'static when I mutate it?
  • Is there some way to get this to work without the extra allocation from creating a new box?

>Solution :

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

From the compiler point of view, you cannot "update" the value from using 'a to using 'static. You are assigning to it, but the type stays the same. Then later you’re trying to convert from Box<&'a i32> to Box<&'static i32>, and it rightfully bails.

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

Yes, but only using unsafe: Playground

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)
    }
}

However, think carefully if you need that: it is likely you can afford an allocation.

Leave a ReplyCancel reply