2016-01-22 11 views
7

ho questo tipo enum:Unwrap tipo interna quando variante enumerazione è noto

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

ora ho una funzione che prende questo tipo come parametro. I noto (per qualche motivo) che l'input è sempre un Cat. Voglio raggiungere questo:

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

Posso scrivere questo più breve e/o più idiomatico?

risposta

11

Non proprio. Quello che ho visto è l'introduzione di una nuova struct per ciascuna variante enum, e quindi metodi sul enum a decomporsi essa:

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 
} 

Naturalmente, non è necessario necessità struct e si poteva solo restituire il u8 , ma potrebbe essere difficile da tracciare.

C'è un barlume di supporto migliore per questo in futuro, tuttavia. I penso è il "efficient code reuse" RFC, ma meglio descritto nel post del blog Virtual Structs Part 3: Bringing Enums and Structs Together. La proposta consisterebbe nel consentire a Animal::Cat di essere di tipo standalone, pertanto il tuo metodo potrebbe accettare uno Animal::Cat e non doversi preoccupare di ciò.


Personalmente, ho quasi sempre preferisco scrivere il codice infallibile nella mia implementazione intrinseca e costringere il chiamante al panico:

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

E probabilmente userei un 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

invece di impl Animal tendo a implorare la caratteristica Into, come [questo esempio di playground] (http://is.gd/jmS3RB). Con le enumerazioni semplici dovrebbe essere relativamente facile avere una macro per generare l'impls, ma non è un pattern che uso tanto, quindi non ho mai avuto il tempo di scriverlo ... –