50

What is the implementation for this function:

fn unbox<T>(value: Box<T>) -> T {
    // ???
}

The only function in the documentation that looks like what I want is Box::into_raw. The following will type check:

fn unbox<T>(value: Box<T>) -> T {
    *value.into_raw()
}

This gives the error error[E0133]: dereference of raw pointer requires unsafe function or block. Wrapping it in an unsafe { ... } block fixes it.

fn unbox<T>(value: Box<T>) -> T {
    unsafe { *value.into_raw() }
}

Is this the correct implementation? If so, why is it unsafe? What does it mean?

Perhaps this question shows my general uncertainty of how Boxs actually work.

Shepmaster
  • 274,917
  • 47
  • 731
  • 969
Calebmer
  • 2,217
  • 5
  • 25
  • 33

1 Answers1

70

Dereference the value:

fn unbox<T>(value: Box<T>) -> T {
    *value
}

Way back in pre-1.0 Rust, heap-allocated values were very special types, and they used the sigil ~ (as in ~T). Along the road to Rust 1.0, most of this special-casing was removed... but not all of it.

This particular speciality goes by the name "deref move", and there's a proto-RFC about supporting it as a first-class concept. Until then, the answer is "because Box is special".

See also:

Shepmaster
  • 274,917
  • 47
  • 731
  • 969
  • Why did I not try that? The `Deref` trait appears to return an `&T`. Do I not understand what the `*` operator does, or are boxes really just special? – Calebmer Feb 16 '17 at 03:20
  • 1
    @Calebmer there's [a difference between `*` and `Deref`](http://stackoverflow.com/q/31624743/155423), **and** boxes are special in this case. – Shepmaster Feb 16 '17 at 03:46
  • 19
    I wish there was an explicit method instead :( – Matthieu M. Feb 16 '17 at 10:03
  • Would much code break if an explicit method was added and the special behavior was removed? Can this be changed in an edition? – Joseph Garvin Jul 19 '20 at 04:34
  • @JosephGarvin It couldn't be a *method* on `Box`, but you could add an associated function (`impl Box { fn whatever(this: Self) -> T }`). This could be added immediately if you felt like submitting a PR. *Removing* the special behavior would likely break far too many things and seems unlikely to be accepted, but potentially possible. – Shepmaster Jul 20 '20 at 13:39
  • But when T is a reference to an object trait &dyn T how can we get the inner concret type ? – tipograf ieromonah Dec 07 '20 at 13:46
  • 1
    @tipografieromonah if you have a reference, you can't get an owned value. See [Cannot move out of borrowed content / cannot move out of behind a shared reference](https://stackoverflow.com/q/28158738/155423); [Cannot move out of borrowed content when trying to transfer ownership](https://stackoverflow.com/q/28258548/155423). If you want a reference, see [How to get a reference to a concrete type from a trait object?](https://stackoverflow.com/q/33687447/155423); [Why doesn't Rust support trait object upcasting?](https://stackoverflow.com/q/28632968/155423). – Shepmaster Dec 07 '20 at 14:22
  • Thiis one clarified my issue https://stackoverflow.com/questions/33687447/how-to-get-a-reference-to-a-concrete-type-from-a-trait-object – tipograf ieromonah Dec 08 '20 at 16:48