I have this enum type:
enum Animal { Dog(i32), Cat(u8), }
Now I have a function that takes this type as parameter. I know (for some reason) that the input is always a Cat
. I want to achieve this:
fn count_legs_of_cat(animal: Animal) -> u8 { if let Animal::Cat(c) = animal { c } else { unreachable!() } }
Can I write this shorter and/or more idiomatic?
Not really. What I have seen is introducing a new struct
for each enum variant, and then methods on the enum to decompose it:
struct Dog(i32); struct Cat(u8); enum Animal { Dog(Dog), Cat(Cat), } impl Animal { fn cat(self) -> Cat { if let Animal::Cat(c) = self { c } else { panic!("Not a cat") } } fn dog(self) -> Dog { if let Animal::Dog(d) = self { d } else { panic!("Not a dog") } } } // Or better an impl on `Cat` ? fn count_legs_of_cat(c: Cat) -> u8 { c.0 }
Of course, you don't need the struct and you could just return the u8
, but that may get hard to track.
There's a glimmer of better support for this in the future, however. I think it's the "efficient code reuse" RFC, but better described in the blog post Virtual Structs Part 3: Bringing Enums and Structs Together. The proposal would be to allow Animal::Cat
to be a standalone type, thus your method could accept an Animal::Cat
and not have to worry about it.
Personally, I almost always prefer to write the infallible code in my inherent implementation and force the caller to panic:
impl Animal { fn cat(self) -> Option<Cat> { if let Animal::Cat(c) = self { Some(c) } else { None } } fn dog(self) -> Option<Dog> { if let Animal::Dog(d) = self { Some(d) } else { None } } }
And I'd probably use a match
impl Animal { fn cat(self) -> Option<Cat> { match self { Animal::Cat(c) => Some(c), _ => None, } } fn dog(self) -> Option<Dog> { match self { Animal::Dog(d) => Some(d), _ => None, } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With