如何获得给定 Trait/Struct 组合的 v-ptr?
How to get the v-ptr for a given Trait/Struct combination?
在 Rust 中,一个 &T
其中 T
是一个 trait
是一个胖引用,它实际上对应于 raw::TraitObject
:
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
使用TraitObject
,可以随意解构和重新构造一个&T
。
然而,虽然通过解构 &T
获得 vtable
很容易,但如果我一开始就没有 &T
,只有 [=14] 怎么办? =] 和 S
;本质上,类似于:
fn make_vptr<T: ?Sized, S>() -> *mut ();
我如何从那里预测 v-ptr?有没有我可以使用的内在函数?
注意:创建 S
(或从稀薄的空气中召唤它)然后创建 &T
引用的天真实现是行不通的;编译器抱怨 T
不一定是 trait
,因此 &T
在大小上是一个指针或两个指针。
我不认为这是目前可能的。
为了使其工作,您需要能够将 T
通用参数限制为 仅 接受特征。你不能这样做。因此,它永远不会让你用 &T
做任何取决于它是一个特征的事情,比如获取 vtable。
一种可能是使用宏来完成神奇的工作:
#![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
没有实现,这段代码将不会编译by 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);
}
在 Rust 中,一个 &T
其中 T
是一个 trait
是一个胖引用,它实际上对应于 raw::TraitObject
:
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
使用TraitObject
,可以随意解构和重新构造一个&T
。
然而,虽然通过解构 &T
获得 vtable
很容易,但如果我一开始就没有 &T
,只有 [=14] 怎么办? =] 和 S
;本质上,类似于:
fn make_vptr<T: ?Sized, S>() -> *mut ();
我如何从那里预测 v-ptr?有没有我可以使用的内在函数?
注意:创建 S
(或从稀薄的空气中召唤它)然后创建 &T
引用的天真实现是行不通的;编译器抱怨 T
不一定是 trait
,因此 &T
在大小上是一个指针或两个指针。
我不认为这是目前可能的。
为了使其工作,您需要能够将 T
通用参数限制为 仅 接受特征。你不能这样做。因此,它永远不会让你用 &T
做任何取决于它是一个特征的事情,比如获取 vtable。
一种可能是使用宏来完成神奇的工作:
#![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
没有实现,这段代码将不会编译by 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);
}