如何获得给定 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);
}