我有一个集合Trait
,即在其上进行迭代,并做了一个功能,然后我想检查的实现者类型,如果它是一个类型的Foo
则垂头丧气,并调用一些Foo中的方法。
基本上,类似于去的东西类型开关和接口转换 。
搜索周围,我发现有关的任何特征 ,但它只能在实施'static
类型。
为了帮助说明我想要的东西:
let vec: Vec<Box<Trait>> = //
for e in vec.iter() {
e.trait_method();
// if typeof e == Foo {
// let f = e as Foo;
// f.foo_method();
//}
}
正如你已经注意到了,只有向下转型与作品Any
特征,是的,它仅支持'static
数据。 你可以找到它为什么如此最近的讨论在这里 。 基本上,对于任意的寿命的引用实施反射是困难的。
这也是不可能的(截至目前,至少)相结合Any
与您的自定义特性容易。 然而, 宏库自动执行Any
你性状最近被创建。 您还可以找到一些讨论它在这里 。
这不是一个具体的防锈问题,尽管词汇可能会有点不同。 要解决这样的问题,不只是在锈,但在任何语言特性的理想方法是添加所需的行为( foo_method
在你的例子)的抽象接口( Trait
):
trait Trait {
fn trait_method(&self);
fn foo_method(&self) {} // does nothing by default
}
struct Foo;
impl Trait for Foo {
fn trait_method(&self) {
println!("In trait_method of Foo");
}
fn foo_method(&self) { // override default behavior
println!("In foo_method");
}
}
struct Bar;
impl Trait for Bar {
fn trait_method(&self) {
println!("In trait_method of Bar");
}
}
fn main() {
let vec: Vec<Box<Trait>> = vec![Box::new(Foo), Box::new(Bar)];
for e in &vec {
e.trait_method();
e.foo_method();
}
}
在这个例子中,我已经把的默认实现foo_method
的Trait
这什么也不做,让你不必在每一个定义它impl
但只有当它适用的一个(或多个)。 你真的应该尝试做上述工作,你再打向下转换到一个具体类型,其中有严重的缺点,即所有,但擦除具有性状放在首位对象的优点之前。
这就是说,存在向下转换可能是必要的情况下,防锈和不支持它 - 虽然界面有点笨重。 您可以向下转换&Trait
,以&Foo
通过增加中间高达投地&Any
:
use std::any::Any;
trait Trait {
fn as_any(&self) -> &Any;
}
struct Foo;
impl Trait for Foo {
fn as_any(&self) -> &Any {
self
}
}
fn downcast<T: Trait + 'static>(this: &Trait) -> Option<&T> {
this.as_any().downcast_ref()
}
as_any
必须是在一个方法Trait
,因为它需要访问具体类型。 现在你可以尝试拨打Foo
一对方法Trait
像这种特质对象( 完整的操场例子 ):
if let Some(r) = downcast::<Foo>(trait_object_ref) {
r.foo_method();
}
为了使这项工作,你必须指定你所期望的类型( ::<Foo>
),并使用if let
来处理时,引用的对象不是实例会发生什么Foo
。 你不能向下转换性状对象的具体类型,除非你知道它到底是什么具体类型。
但是,如果你需要知道具体类型,特质对象是几乎无用呢! 你或许应该使用一个enum
如果省略某个地方处理的变体代替,这样你会得到编译时错误。 此外,您不能使用Any
与非'static
结构,因此,如果任何Foo
可能需要包含一个参考,这样的设计是死路一条。 最好的解决办法,如果你能做到这一点,是添加foo_method
的特质本身。