However, variant c does not, probably because the new
function takes only values of the same type which is not the case since Fooer != i32
.
No, it's because there is no new
function for Box<dyn Fooer>
. In the documentation:
impl<T> Box<T>
pub fn new(x: T) -> Box<T>
Most methods on Box<T>
allow T: ?Sized
, but new
is defined in an impl
without a T: ?Sized
bound. That means you can only call Box::<T>::new
when T
is a type with a known size. dyn Fooer
is unsized, so there simply isn't a new
function to call.
In fact, that function can't exist in today's Rust. Box<T>::new
needs to know the concrete type T
so that it can allocate memory of the right size and alignment. Therefore, you can't erase T
before you send it to Box::new
. (It's conceivable that future language extensions may allow functions to accept unsized parameters; however, it's unclear whether even unsized_locals
would actually enable Box<T>::new
to accept unsized T
.)
For the time being, unsized types like dyn Fooer
can only exist behind a "fat pointer", that is, a pointer to the object and a pointer to the implementation of Fooer
for that object. How do you get a fat pointer? You start with a thin pointer and coerce it. That's what's happening in these two lines:
let d: Box<Fooer> = Box::new(32); // works, creates a Box<Fooer>
let e: Box<Fooer> = Box::<i32>::new(32); // works, creates a Box<Fooer>
Box::new
returns a Box<i32>
, which is then coerced to Box<Fooer>
. You could consider this a conversion, but the Box
isn't changed; all the compiler does is stick an extra pointer on it and forget its original type. rodrigo's answer goes into more detail about the language-level mechanics of this coercion.
Hopefully all of this goes to explain why the answer to
Is there a way to create a Box<Fooer>
directly from an i32
?
is "no": the i32
has to be boxed before you can erase its type. It's the same reason you can't write let x: Fooer = 10i32
.
Related
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…