6

I'm trying to use enum variants to capture data which is heterogeneous in nature (has different collections of fields) but which is of the same "type" from a protocol perspective. However, I'm not sure how to implement subtype-specific methods and traits. Here is a minimal example of how I can create an enumeration of Data and I can use enum variant constructors to specify the types, but if I implement a trait on the variant, calling that function is not something I've figured out how to do.

use std::fmt;

enum Data {
    N(NData),
    S(SData),
}

struct NData {
    numeric: u32,
}

impl fmt::Display for NData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.numeric)
    }
}

struct SData {
    stringy: Vec<String>,
}

fn main() {
    let d_n: Data = Data::N(NData { numeric: 0x0 });
    let n = NData { numeric: 0xff };

    // Fails, fmt::Display not implemented for Data
    println!("{}", d_n);

    // Just fine!
    println!("{}", n);
}
E_net4
  • 27,810
  • 13
  • 101
  • 139
JawguyChooser
  • 1,816
  • 1
  • 18
  • 32
  • note that you probably just want to derive [`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html#examples) trait – Stargateur Jul 17 '19 at 00:51
  • 2
    @Stargateur: if this was all I really had to do, sure! But this is a representative simplification of the actual traits I need to implement. – JawguyChooser Jul 17 '19 at 14:55

1 Answers1

17

One possible solution could be to implement your trait for the variants as well as for the enum, which as you can see here only calls the specific implementations of the variants:

use std::fmt;

struct NData {
    numeric: u32,
}

impl fmt::Display for NData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.numeric)
    }
}

struct SData {
    strings: Vec<String>,
}

impl fmt::Display for SData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.strings)
    }
}

enum Data {
    N(NData),
    S(SData),
}

impl fmt::Display for Data {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Data::N(n_data) => n_data.fmt(f),
            Data::S(s_data) => s_data.fmt(f),
        }
    }
}

fn main() {
    let n = NData { numeric: 0xff };
    let s = SData { strings: vec!["hello".to_string(), "world".to_string()] };

    println!("{}", n);
    println!("{}", s);

    let d_n = Data::N(n);
    let d_s = Data::S(s);

    println!("{}", d_n);
    println!("{}", d_s);
}

Which will produce the following output:

255
["hello", "world"]
255
["hello", "world"]
Peter Varo
  • 11,726
  • 7
  • 55
  • 77