Consider the code:
use std::boxed::Box;
use std::mem::transmute;
trait Total {
fn total(&self) -> i32;
}
#[derive(Debug)]
struct S {
a: i32,
b: i32,
c: i32,
}
impl S {
fn new() -> S {
S { a: 2, b: 3, c: 4 }
}
}
impl Total for S {
fn total(&self) -> i32 {
self.a + self.b + self.c
}
}
fn main() {
let b: Box<Total> = Box::new(S::new());
unsafe {
let s: Box<S> = std::mem::transmute(b);
println!("S = {:?}", s);
}
}
This gives the error:
error[E0512]: transmute called with differently sized types: Box<Total> (128 bits) to Box<S> (64 bits)
--> src/main.rs:30:29
|
30 | let s: Box<S> = std::mem::transmute(b);
| ^^^^^^^^^^^^^^^^^^^
Given that Box<Total>
is really a Box<S>
, why do we get this error?
Unlike most languages featuring OO-concepts which embed virtual pointers in class
, Rust uses the fat-pointer approach in which it carries both the virtual pointer and struct
pointer alongside each other.
As a result, the layout of Box<Trait>
for a S
is:
+-------+-------+
| v-ptr | S-ptr |
+-------+-------+
which is 128-bits on a 64-bits platform.
As for downcasting, at the moment you can use the Any
type and its downcast_ref
and downcast_mut
.
You may also be interested in the query_interface crate for more elaborate use cases.
A trait object, such as Box<Trait>
or &Trait
, contains two pointers:
Two pointers (on 64-bit machines) adds up to 128 bits.
A Box<Struct>
only contains a single pointer, directly to the data. No vtable is needed because the specific methods are able to be resolved statically at compile time. This single pointer is only 64 bits.
Given that
Box<Total>
is really aBox<S>
They are not. If they were the same, why would they have different names? :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With