2016-01-22 7 views
7

ich diesen Aufzählungstyp haben:Abwickelwerkzeug Innen Typ, wenn Enum Variante bekannt ist

enum Animal { 
    Dog(i32), 
    Cat(u8), 
} 

Jetzt habe ich eine Funktion, die diese Art als Parameter übernimmt. Ich weiß (aus irgendeinem Grund), dass der Eingang immer ein Cat ist. Ich möchte dies erreichen:

fn count_legs_of_cat(animal: Animal) -> u8 { 
    if let Animal::Cat(c) = animal { c } else { unreachable!() } 
} 

Kann ich diese kürzere und/oder mehr idiomatische schreiben?

Antwort

11

Nicht wirklich. Was ich gesehen habe, ist es, eine neue struct für jede Enum-Variante einzuführen, und dann Methoden auf dem ENUM es zersetzen:

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 
} 

Natürlich, du nicht Notwendigkeit die Struktur und man konnte nur die u8 zurückkehren , aber das kann schwer zu verfolgen sein.

Dafür gibt es in der Zukunft jedoch einen besseren Hinweis. I denke, ist es die "efficient code reuse" RFC, aber besser im Blog Post Virtual Structs Part 3: Bringing Enums and Structs Together beschrieben. Der Vorschlag wäre, Animal::Cat als eigenständigen Typ zuzulassen, also könnte Ihre Methode eine Animal::Cat akzeptieren und muss sich nicht darum kümmern.


Persönlich bevorzuge ich fast immer den unfehlbar Code in meiner inhärenten Implementierung zu schreiben und die Anrufer in Panik erzwingen:

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 
     } 
    } 
} 

Und ich würde wahrscheinlich ein 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, 
     } 
    } 
} 
+2

verwenden anstelle des impl Tiers tendiere ich dazu, das Into-Merkmal zu impli- zieren, wie [dieses Spielplatzbeispiel] (http://is.gd/jmS3RB). Bei einfachen Enums sollte es relativ einfach sein, ein Makro zu haben, um die Impls zu erzeugen, aber es ist kein Muster, das ich so oft benutze, so dass ich nie dazu gekommen bin es zu schreiben ... –

Verwandte Themen