我有一个Trait
的集合,一个迭代它并执行某些操作的函数,然后我想检查一下实现者类型,如果它是Foo
类型,那么将它向下转换并调用一些Foo方法。
基本上类似于Go type-switch和interface 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();
//}
}
答案 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
添加到特征本身。