我可以用特征对象键入内省然后向下转换吗?

时间:2015-01-11 21:35:00

标签: rust

我有一个Trait的集合,一个迭代它并执行某些操作的函数,然后我想检查一下实现者类型,如果它是Foo类型,那么将它向下转换并调用一些Foo方法。

基本上类似于Go type-switchinterface conversion

我四处搜索Any trait,但它只能在'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();
    //}
}

2 个答案:

答案 0 :(得分:8)

正如您所注意到的,向下转换仅适用于Any特征,是的,它仅支持'static数据。您可以找到最近的讨论原因here。基本上,实现任意生命周期参考的反射是困难的。

Any与您的自定义特征轻松组合也是不可能的(至少现在如此)。但是,最近创建了macro library用于自动实现特征Any的{​​{3}}。您还可以在其上找到一些讨论here

答案 1 :(得分:3)

虽然词汇表可能略有不同,但这不是特定于Rust的问题。解决这样的问题的理想方法,不仅是使用Rust中的特征,而且使用任何语言,都是将所需的行为(在您的示例中为foo_method)添加到抽象接口(Trait):< / p>

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中定义它(s)适用的地方。在你采用向下转换为具体类型之前,你应该真的尝试完成上述工作,这具有严重的缺点,除了首先消除了具有特征对象的优点之外。

也就是说,有些情况下可能需要向下转换,而Rust确实支持它 - 尽管界面有点笨重。您可以通过向&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(); } 方法(complete playground example):

::<Foo>

要使其工作,您必须指定您期望的类型(if let)并使用Foo来处理引用的对象不是enum的实例时发生的情况。除非您确切地知道具体的具体类型,否则不能将特征对象向下转换为具体类型。

但是如果你需要知道具体的类型,那么特质对象几乎是无用的!您可能应该使用Any代替,以便在省略某处处理变体时会遇到编译时错误。此外,您不能将'static与非Foo结构一起使用,因此如果任何foo_method可能需要包含引用,则此设计是死路一条。如果可以的话,最好的解决方案是将import re from machine import UART uart = UART(2, 9600) pattern=r"b'[0-9]+" while True: if uart.any(): data=uart.read() all_items=[] track=[] for i in data.split(','): pr=re.search(pattern,i) if len(track)==5: break else: if pr!=None: track.append(pr.group()) all_items.append(pr.group()) else: all_items.append(i) print(all_items) this would be the code apllied to my project, but I get this error: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 12, in <module>`enter code here` TypeError: can't convert 'str' object to bytes implicitly 添加到特征本身。