是否可以在集合中存储实现相同非对象安全特性的不同具体类型



像这样的特性会阻止&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);
}

永久链接到操场

您可以为任何实现T1T2:的类型创建一个自动实现的超级特征

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);

可运行的游乐场链接

最新更新