3

Let's say I have the structs "F1" and "F2" that implement the Trait "Foo".
Now I want to write a function that accepts Foo and returns Bar.

trait Foo {
    fn get_bar(&self) -> &Bar
}
fn do_match(f: &Foo) -> &Bar {
    &match *f {
       F1 => { f.get_bar() } // Error: mismatched types: expected `Foo`, found an enum or structure pattern
       F2 => { f.get_bar().modify_somehow(3f64) }
    }
}

Is it possible to match against structs implementing the trait Foo?

uwap
  • 110
  • 7

1 Answers1

2

No, match cannot match on the concrete type of a value. Considering that match requires the patterns to be exhaustive, and that traits are open (types from other modules or other crates can implement your trait), you could never cover all cases (unless you have a simple variable binding like x on the last arm). match works better on enums, which are closed (the set of variants is fixed in the enum's definition).

You can introduce a second trait to do dynamic dispatch. Note that you can define the second trait and its implementations in a different module or a different crate from where F1 and F2 are defined.

trait Foo2 {
    fn get_bar2(&self) -> &Bar;
}

impl Foo2 for F1 {
    fn get_bar2(&self) -> &Bar {
        self.get_bar()
    }
}

impl Foo2 for F2 {
    fn get_bar2(&self) -> &Bar {
        self.get_bar().modify_somehow(3f64)
    }
}

fn do_match(f: &Foo2) -> &Bar {
    f.get_bar2()
}
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • Thanks. It seems that there is no possible way to do what I wanted to do. – uwap Sep 26 '14 at 03:48
  • Could you elaborate on what you wanted to do? – Francis Gagné Sep 26 '14 at 04:00
  • I'm having tupel structs named after units. So Meter(T), Centimeter(T) and so on. They all implement the Trait Distance. I also have tupel structs named Hour(T), Second(T) and so on implementing the Trait Time. I want to define the division Distance / Time returning Velocity. Now Meter / Second should return the type MetersPerSecond and Kilometers / Hour the type MetersPerHour and so on. The thing is that I have like 5 distance structs and 4 time structs (the number still gets increased over time), so 5*4 = 20 possible combinations. – uwap Sep 26 '14 at 04:16
  • 1
    Two other options to consider: use an `enum` instead of a `trait`, which each of your tuple structs as a variant (if you don't need extensibility), or normalize values to a particular unit for each trait (e.g. `Meter` for `Distance`) and only implement the operation on the normalized types. The operation to normalize would be a method of each trait and the return type would be the normalized type (e.g. `Meter`, `Second`, etc.). Then you denormalize the result. – Francis Gagné Sep 26 '14 at 23:58
  • Yeah. Thanks. I managed to get it working. Not as I intended it to work originally, but the implementation using enums is probably a better way to go. – uwap Sep 27 '14 at 01:58