我有两个特征,一个是序数 ( Foo
),另一个是通用 ( TypedFoo<T>
)。我有几个结构,每个结构都实现了两个特征。
是否可以从 Foo
转换至 TypedFoo<T>
, 不转换为中间结构?
trait Foo {
fn f(&mut self);
}
trait TypedFoo<T> {
fn get(&self) -> T;
}
#[derive(Clone)]
struct Data(i32);
impl Foo for Data {
fn f(&mut self) {
self.0 += 1;
}
}
impl TypedFoo<Data> for Data {
fn get(&self) -> Data {
self.clone()
}
}
//struct Data2(f64);
//impl Foo for Data2...
//impl TypedFoo<Data2> for Data2..
fn main() {
let v: Vec<Box<Foo>> = vec![Box::new(Data(1))];
}
我可以改变Foo
对此:
trait Foo {
fn f(&mut self);
fn get_self(&self) -> &Any;
}
然后得到v[0].get_self()
downcast_ref
至 Data
, 然后 Data
至 &TypedFoo<Data>
.
但是有没有可能得到&TypedFoo<Data>
来自 &Foo
在不知道“数据类型”的情况下,Any
的一些模拟但是为了一个特质。
我想象这样的语法:
let foo: &Foo = ...;
if let Some(typed_foo) = foo.cast::<Data>() {
}
我的问题不同于Can I cast between two traits? 因为我有一个通用特征和一个顺序特征。如果我有两个序数特征,那么解决方案将很简单:
trait Foo {
fn f(&mut self);
fn as_typed_foo(&self) -> &TypedFoo;
}
自 TypedFoo
是通用的,该问题的答案都没有帮助我。一种可能的解决方案是:
trait Foo {
fn f(&mut self);
fn cast(&mut self, type_id: ::std::any::TypeId) -> Option<*mut ::std::os::raw::c_void>;
}
我不确定投 *mut TypedFoo<T>
有多安全-> *mut ::std::os::raw::c_void
然后回到*mut TypedFoo<T>
.
最佳答案
你想要的函数的签名是
fn convert<T>(x: &Box<Foo>) -> &TypedFoo<T>
为了类型检查这个签名编译器必须知道 Box
里面的类型工具 TypedFoo<T>
对于一些 T
.但是转换为 trait-object 会删除有关真实类型的信息。这意味着不可能静态类型检查此函数的签名。
所以我们需要动态地进行,如果我们想使用当前 crate 不知道的类型,我们需要求助于 unsafe。
一个选项是限制一组类型,可以在TypedFoo
中使用, 并在 Foo
中提供转换函数特征。这样可以避免不安全。
第二个选项是添加到 trait Foo
一个函数,它返回一个对 (TypeId, *const ())
的切片.该指针是指向函数的类型删除指针,它进行实际转换。转换函数查找所需的类型标识符并执行相应的函数。
为了演示,我使用了 Vec
而不是切片 conversion_registrar
.但是将返回类型更改为 &'static [(TypeId, *const ())]
应该不会太难, 使用 lazy_static crate 。
关于rust - 从没有 Self 类型的序数中获取通用特征?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44368642/