Match pattern for wrapped and unwrapped enum values

enum Funny {
    Empty,
    Alpha(String),
    Beta(String),
    Gamma(String),
    .
    .
    .

}
impl Funny {
    pub fn _unwrap(&self) -> String {
        match self {
            Empty => String::new(),
            Alpha(v) => v.to_string(),
            Beta(v) => v.to_string(),
            .
            .
            .
        }
    }
}

As you can see in the code, it becomes a very repetitive operation. If the compiler could accept _(v) => v it would have been easy but it doesn't.

Adding it in a code review to also know if there's a bettter, more idiomatic way of doing it.
I understand it is a siren to use Option<> here but that would mean losing the enum style information. Skipping elaboration for brevity.

You can use a declarative macro to reduce the duplication:

enum Funny {
    Empty,
    Alpha(String),
    Beta(String),
    Gamma(String),
}

impl Funny {
    pub fn _unwrap(&self) -> String {
        macro_rules! match_helper {
            ($($variant:ident),*) => {
                match self {
                    Self::Empty => String::new(),
                    $( Self :: $variant (v) => v.to_string(), )*
                }
            }
        }
    
        match_helper!(Alpha, Beta, Gamma)
    }
}

Option + a struct with a String and an enum that describes its kind is also an option. I don't see why you would lose the enum style information.

struct Funny(Option<FunnyInner>);
struct FunnyInner {
    kind: FunnyKind,
    v: String,
}
enum FunnyKind {
    Alpha,
    Beta,
    Gamma
}

impl Funny {
    pub fn _unwrap(&self) -> String {
        match &self.0 {
            Some(FunnyInner { v, .. }) => v.to_string(),
            None => String::new(),
        }
    }
}
4 Likes

Damn! Both these solutions are awesome. I have never learned to use declarative macros and this seems like a good excuse. I don't even consider macros as a dev tool and just tend to stay away from their inner workings.

The second solution makes a lot of sense. I think the code could grow thicker when I decide to add other type of values to it. But that sounds sus just saying it out loud.

Thank you for both of them!

Another way is to use an OR pattern (|) with the same variable name (v) for each String. As long as v is the same type in each sub-pattern you can implement the body of the pattern only once.

    impl Funny {
        pub fn _unwrap(&self) -> String {
            match self {
                Funny::Empty => String::new(),
                Funny::Alpha(v) | Funny::Beta(v) | Funny::Gamma(v) => {
                    v.to_string()
                }
            }
        }
    }

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.