Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement a trait for an enum and its respective variants?

Tags:

enums

rust

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);
}
like image 625
JawguyChooser Avatar asked Dec 18 '22 16:12

JawguyChooser


1 Answers

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"]
like image 89
Peter Varo Avatar answered May 20 '23 20:05

Peter Varo