如何获得给定Trait / Struct组合的v-ptr?

时间:2015-05-17 14:40:55

标签: rust trait-objects

在Rust中,&T Ttrait是一个胖引用,实际上对应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 个答案:

答案 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。