在Rust中,&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
是一个指针或两个指针大小。
答案 0 :(得分:3)
可能是使用宏来完成神奇的工作:
#![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
{1}}(感谢转让)。
然后,它可以直接使用:
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);
}
答案 1 :(得分:0)
我不相信这是目前可能的。
为了实现这一点,您需要能够将T
通用参数限制为仅接受特征。你不能这样做。因此,它永远不会让你做&T
的任何事情,这取决于它是一个特征,比如获得vtable。