【问题标题】:How to get the v-ptr for a given Trait/Struct combination?如何获取给定 Trait/Struct 组合的 v-ptr?
【发布时间】:2018-04-30 01:51:56
【问题描述】:

在 Rust 中,&T 其中Ttrait 是一个胖引用,它实际上对应于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(或凭空变出)然后创建&amp;T 引用的幼稚实现是行不通的;编译器抱怨T 不一定是trait,因此&amp;T 的大小不是一个指针就是两个指针。

【问题讨论】:

    标签: rust trait-objects


    【解决方案1】:

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

    #![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(..) 检查&amp;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);
    }
    

    【讨论】:

    • 不是通用的(不幸的是),因为它不能在通用函数中调用,但它应该足以满足我的目的。谢谢!
    【解决方案2】:

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

    为了使其工作,您需要能够将T 泛型参数限制为接受特征。你不能这样做。因此,它永远不会让您对 &amp;T 做任何取决于它作为特征的事情,例如获取 vtable。

    【讨论】:

    • 这正是阻碍我的原因,是的。
    猜你喜欢
    • 2021-12-26
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    • 1970-01-01
    • 2020-09-12
    相关资源
    最近更新 更多