Как получить v-ptr для данной комбинации Trait/Struct?
В Русте &T
где T
это trait
это жирная ссылка, которая на самом деле соответствует raw::TraitObject
:
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
С помощью TraitObject
можно деконструировать и реконструировать &T
на досуге.
Однако при получении vtable
от разрушения &T
легко, что если у меня никогда не будет &T
во-первых, но просто T
а также S
; по сути, что-то вроде:
fn make_vptr<T: ?Sized, S>() -> *mut ();
Как я мог угадать V-PTR оттуда? Есть ли что-то, что я мог бы использовать?
Примечание: наивная реализация создания S
(или колдовать его из воздуха), а затем сделать &T
ссылка не работает; компилятор жалуется, что T
не обязательно trait
и поэтому &T
или один указатель или два указателя в размере.
2 ответа
Можно использовать макрос для магической работы:
#![feature(raw)]
macro_rules! make_vptr(
($S:ty, $T:ty) => ({
let s: &$S = unsafe { ::std::mem::uninitialized() };
let t: &$T = s;
let r: ::std::raw::TraitObject = unsafe { ::std::mem::transmute(t) };
r.vtable
})
);
Этот код не скомпилируется, если T
это не черта (спасибо transmute(..)
проверяя это &T
жирный указатель) или если T
не реализуется S
(благодаря назначению).
Затем его можно использовать напрямую:
use std::fmt::Display;
fn main() {
let u32_display_vtable = make_vptr!(u32, Display);
let x = 42u32;
let disp: &Display = unsafe {
::std::mem::transmute(::std::raw::TraitObject {
data: &x as *const _ as *mut _,
vtable: u32_display_vtable,
})
};
println!("{}", disp);
}
Я не верю, что это возможно в настоящее время.
Для того чтобы это работало, вы должны быть в состоянии ограничить T
универсальный параметр, чтобы принимать только черты. Вы не можете сделать это. В результате он никогда не позволит вам ничего сделать с &T
это зависит от того, является ли это чертой, такой как получение vtable.