如何获得给定特征/结构组合的 v-ptr?



在 Rust 中,Ttrait&T是一个胖引用,它实际上对应于raw::TraitObject

pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}

使用TraitObject,人们可以在闲暇时解构和重建&T

然而,虽然从解构&T中获得vtable很容易,但如果我一开始就没有&T,而只是一个TS怎么办;本质上,大致如下:

fn make_vptr<T: ?Sized, S>() -> *mut ();

我怎么能从那里占卜 v-ptr?我可以使用任何内在因素吗?

注意:创建S(或凭空变出它)然后进行&T引用的幼稚实现不起作用;编译器抱怨T不一定是trait,因此&T的大小要么是一个指针,要么是两个指针。

一种可能性是使用宏来完成神奇的工作:

#![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。

最新更新