我想声明一个接受特征对象的通用函数,只接受特征对象。我想要这个,因为我想键入擦除这些并将它们作为TraitObject
对象传递到ABI边界。
这样写的函数将无法编译......
fn f<T: ?Sized>(t: &T) -> std::raw::TraitObject {
unsafe { std::mem::transmute(t) }
}
...出现以下错误:
error[E0512]: transmute called with differently sized types: &T (pointer to T) to std::raw::TraitObject (128 bits)
我理解为什么编译器抱怨不同的大小:&T
可以是指向具体类型的指针(如&i32
),它是单指针(64位)或特征对象(比如&Display
),它将是两个指针,其布局与std::raw::TraitObject
(128位)相同。
只要&T
是特征对象,此函数就可以正常,即T
是特征。有没有办法表达这个要求?
答案 0 :(得分:3)
不可能证明是消极的...但据我所知,答案是否定的,抱歉。
TraitObject
的表示是不稳定的,特别是因为将来Rust可能能够将多个虚拟指针添加到单个数据指针(例如代表&(Display + Eq)
)。
同时,我通常使用低级内存技巧来读取虚拟指针和数据指针,然后自己构建TraitObject
;通过致电mem::size_of
来保护,以确保&T
的{{1}}大小正确,因为*mut ()
表示?Sized
或不Sized
(而非!Sized
})。
答案 1 :(得分:3)
如果你use transmute_copy
instead,你可以让编译器忽略大小不匹配。但是,这意味着您必须自己处理此类问题,例如:自己检查尺寸,如果不匹配可能会感到恐慌。不这样做会导致未定义的行为。
fn f<T: ?Sized>(t: &T) -> std::raw::TraitObject {
assert!(std::mem::size_of::<&T>() == std::mem::size_of::<std::raw::TraitObject>());
unsafe { std::mem::transmute_copy(&r) }
}
答案 2 :(得分:1)