像这样的特性会阻止&dyn DoAction
,因为它有一个通用函数:
trait DoAction {
fn action<T: T1 + T2>(&self, s: &T) {
s.action_t1();
s.action_t2();
}
}
有没有一种方法可以编写一个函数,其中Vec
包含不同的具体类型,但它们都实现了特性DoAction
?
fn run_all(runners: Vec<&impl DoAction>) {}
我想解决的主要问题是能够在这些不同的具体类型上循环,但我不能像How do I create a异类collection of object中所描述的那样使用Vec<&dyn T>
trait object?由于一般特征函数。
例如:
struct SA {
sa: u32,
}
struct SB {
sb: u32,
}
trait T1 {
fn action_t1(&self) -> bool {
true
}
}
trait T2 {
fn action_t2(&self) -> bool {
true
}
}
impl T1 for SA {}
impl T1 for SB {}
impl T2 for SA {}
impl T2 for SB {}
impl T1 for &SA {}
impl T1 for &SB {}
impl T2 for &SA {}
impl T2 for &SB {}
trait DoAction {
fn action<T: T1 + T2>(&self, s: &T) {
s.action_t1();
s.action_t2();
}
}
struct Runner1 {}
impl DoAction for Runner1 {}
struct Runner2 {}
impl DoAction for Runner2 {}
fn run_all(runners: Vec<&impl DoAction>, s: (impl T1 + T2)) {
for r in runners {
r.action(&s);
}
}
fn main() {
let a = SA { sa: 123 };
let r1 = Runner1 {};
let r2 = Runner2 {};
let ls = vec![&r1, &r2];
run_all(ls, &a);
}
游乐场
由于这样的函数只适用于某些具体类型,因此可以通过创建一个特性来解决这个问题;具体化";方法,并为实现DoAction
:的所有类型实现它
trait DoConcreteAction<T> {
fn concrete_action(&self, s: &T);
}
impl<T, U> DoConcreteAction<U> for T
where
T: DoAction,
U: T1 + T2,
{
fn concrete_action(&self, s: &U) {
self.action(s)
}
}
fn run_all<T>(runners: Vec<&dyn DoConcreteAction<T>>, s: &T) {
for r in runners {
r.concrete_action(&s);
}
}
fn main() {
let a = SA { sa: 123 };
let r1 = Runner1 {};
let r2 = Runner2 {};
let ls: Vec<&dyn DoConcreteAction<SA>> = vec![&r1, &r2];
run_all(ls, &a);
}
永久链接到操场
您可以为任何实现T1
和T2
:的类型创建一个自动实现的超级特征
trait T1AndT2: T1 + T2 {}
impl<T: T1 + T2> T1AndT2 for T {}
然后更改DoAction
以接受特征对象(T1AndT2
(而不是泛型:
trait DoAction {
fn action(&self, s: &dyn T1AndT2) {
s.action_t1();
s.action_t2();
}
}
既然DoAction
不使用泛型,就可以创建DoAction
对象的向量:
let ls: Vec::<&dyn DoAction> = vec![&r1, &r2];
并将其用于您的功能:
run_all(ls);
可运行的游乐场链接