我所能做的输入与特质对象自省,然后垂头丧气呢?(Can I do type introspectio

2019-10-23 09:13发布

我有一个集合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();
    //}
}

Answer 1:

正如你已经注意到了,只有向下转型与作品Any特征,是的,它仅支持'static数据。 你可以找到它为什么如此最近的讨论在这里 。 基本上,对于任意的寿命的引用实施反射是困难的。

这也是不可能的(截至目前,至少)相结合Any与您的自定义特性容易。 然而, 宏库自动执行Any你性状最近被创建。 您还可以找到一些讨论它在这里 。



Answer 2:

这不是一个具体的防锈问题,尽管词汇可能会有点不同。 要解决这样的问题,不只是在锈,但在任何语言特性的理想方法是添加所需的行为( 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_methodTrait这什么也不做,让你不必在每一个定义它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的特质本身。



文章来源: Can I do type introspection with trait objects and then downcast it?
标签: rust