2

In Rust, a &T where T is a trait is a fat reference, which actually corresponds to raw::TraitObject:

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

Using TraitObject, one can de-construct and re-construct a &T at leisure.

However, while obtaining the vtable from de-constructing a &T is easy, what if I never have the &T in the first place, but just a T and S; essentially, something along the lines of:

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

How could I divine the v-ptr from there? Is there any intrinsic I could use?

Note: the naive implementation of creating a S (or conjuring it from thin-air) and then making a &T reference does not work; the compiler complains that T is not necessarily a trait and therefore that &T is either one pointer or two pointers in size.

4

2 回答 2

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(感谢分配)实现,则此代码将不会编译。

然后,就可以直接使用了:

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);
}
于 2015-05-17T16:09:55.150 回答
0

我不相信这是目前可能的。

为了使它起作用,您需要能够将T泛型参数限制为接受特征。你不能这样做。因此,它永远不会让你做任何&T取决于它是一个特征的事情,比如获取 vtable。

于 2015-05-17T16:09:13.263 回答