Are there any alternatives to enums or trait objects to process two collections of items of different concrete types?

Viewed 431

I need to take two Vecs of different concrete types and process each combination of list A and B. I can see two ways to do it:

  1. enum * enum

    Wrap the concrete type in an enum, use match, use generic functions in trait signatures.

  2. dyn * dyn

    Use trait objects, and never use generic functions in the trait signatures.

Are there any other ways do to this?

My aim is a nested loop where the concrete types of each loop can be different types implementing the same trait, or something semantically equal.

struct S1 {}
struct S2 {}

struct SA {}
struct SB {}

trait TTakerConcrete {
    fn do_action_concrete<T: TGiver>(&self, g: &T) {
        // Do some custom processing per struct
        g.give_data();
    }
}

trait TTakerDyn {
    fn do_action_dyn(&self, g: &dyn TGiver) {
        // Do some custom processing per struct
        g.give_data();
    }
}

trait TGiver {
    fn give_data(&self) -> String {
        "diff string per struct".to_string()
    }
}

// Nums are takers.
impl TTakerDyn for &S1 {}
impl TTakerDyn for &S2 {}
impl TTakerConcrete for &S1 {}
impl TTakerConcrete for &S2 {}
impl TTakerDyn for S1 {}
impl TTakerDyn for S2 {}
impl TTakerConcrete for S1 {}
impl TTakerConcrete for S2 {}

// Letters are givers.
impl TGiver for &SA {}
impl TGiver for &SB {}
impl TGiver for SA {}
impl TGiver for SB {}

fn dyn_dyn(t: Vec<&dyn TTakerDyn>, g: Vec<&dyn TGiver>) {
    for n in t {
        for l in &g {
            n.do_action_dyn(*l);
        }
    }
}

fn enum_enum(t: Vec<&Nums>, g: Vec<&Letters>) {
    for n in t {
        for l in &g {
            match n {
                Nums::S1(s1) => match l {
                    Letters::SA(sa) => s1.do_action_concrete(sa),
                    Letters::SB(sb) => s1.do_action_concrete(sb),
                },
                Nums::S2(s2) => match l {
                    Letters::SA(sa) => s2.do_action_concrete(sa),
                    Letters::SB(sb) => s2.do_action_concrete(sb),
                },
            };
        }
    }
}

enum Nums {
    S1(S1),
    S2(S2),
}
enum Letters {
    SA(SA),
    SB(SB),
}

fn main() {}

playground

0 Answers
Related