2010-09-10 1 views
3

Je suis noteur nouveau à scala, mais au fond ont trouvé mon chemin ...comment exposer test pour un match de modèle

Ici, je demande la méthode recommandée/meilleures pratiques/idiomatiques de la mise en œuvre ceci:

  • interne, MyClass utilise un état de type, qui est mis en œuvre par une hiérarchie fermée des classes de cas
  • mais sur l'API, seule une partie prédicat booléen doit être exposé, qui obtient mis en œuvre par correspondance contre l'état (interne).

Actuellement, ma mise en œuvre est le long des lignes de ...

def isSane: Boolean = state match { 
    case Ok(_,'valid) => true 
    case _   => false 
} 

Mais cette solution me sent maladroit, comme si quelque chose dans l'expression 3 lignes de code qui ne dispose que le contenu de l'information vaut une ligne de code. En fait, ce que je voudrais écrire serait:

def isSane: boolean = state matches Ok(_, 'valid) 

Probablement/probable qu'il est possible de mettre en œuvre un opérateur approprié vous dans scala, mais avant que je regarde dans cela, je voudrais savoir quelle serait la d'habitude façon de résoudre ce problème. Peut-être y a-t-il aussi une implémentation de bibliothèque existante?

Répondre

1

Si la propriété est Symbol statiquement connu pour être une propriété du type de state:

def isSane: Boolean = 
    state.secondSymbolPropertyWhateverItsCalled == 'valid 

Si vous ne savez pas que state est un Ok, puis:

def isSane: Boolean = 
    state.isInstanceOf[Ok] && state.asInstanceOf[Ok].symbolProp == 'valid 

mais à ce stade, ce n'est pas vraiment supérieur à ce que vous avez écrit.

Enfin, vous pouvez simplement définir isSane sur la hiérarchie des types et déléguer:

def isSane: Boolean = 
    state.isSane 
+0

Dans l'exemple que j'avais en tête, le point est simplement de faire correspondre une propriété dans l'un des états possibles. – Ichthyo

+0

bien ... une autre question intéressante serait en ce qui concerne la performance. – Ichthyo

+0

... Je suppose que le compilateur génère quelque chose de similaire à votre deuxième exemple de la correspondance de modèle d'origine, tandis qu'OTOH, en plaçant l'isSane dans la hiérarchie d'état permettrait d'échanger du stockage supplémentaire pour une amélioration des performances. Mais de toute façon, dans la plupart des cas, de telles différences n'auront aucune importance compte tenu des performances des systèmes actuels. – Ichthyo

2

je peux être vieux jeu, mais pourquoi ne pas utiliser le polymorphisme?

trait State { def sane: Boolean } 

trait InvalidState extends State { def sane = false } 

case class Ok(whatever: Whatever, s: Symbol) extends State { 
    def sane = { s == 'valid } 
} 

case class Failure(msg: String) extends InvalidState 

case class WarmingUp extends InvalidState 

// ... 

def isSane(): Boolean = state.sane 

Bien sûr, si ce n'est pas une possibilité pour une raison quelconque, vous pouvez généraliser Daniel's solution peu:

class Matcher[T](o: T) { 
    def matches(pf: PartialFunction[T, Unit]) = pf isDefinedAt o 
} 

object Matcher { 
    implicit def o2matcher[T](o: T): Matcher[T] = new Matcher(o) 
} 

// then 
def isSane = state matches { case Ok(_,'valid) => } 
+0

Il me semble que 'State' n'est pas la classe sur laquelle' sane' est appelée, juste une classe utilisée en interne. –

+0

J'opterais pour la solution classique OO-style dès que le contrôle devient plus compliqué à mettre en œuvre. Je ne considère pas cela démodé, il suffit de me former la * lisibilité * est le critère. C'est-à-dire, si la solution basée sur le modèle de correspondance peut être écrite sur une ligne et d'une manière qui communique immédiatement mon intention, alors je préférerais l'approche classique – Ichthyo

2

je ferais quelque chose comme ceci:

abstract class State { 
    def matches(pf: PartialFunction[State, Unit]) = pf isDefinedAt this 
} 

// then 

def isSane = state matches { case Ok(_,'valid) => } 

Parce que matches est défini pour recevoir une fonction partielle, vous pouvez le suivre avec une fonction littérale avec seulement les instructions de cas qui devraient aboutir à true. Vous n'avez rien à renvoyer, car la fonction partielle est définie comme renvoyant Unit. Enfin, la méthode matches utilise la méthode des fonctions partielles isDefinedAt pour vérifier s'il existe une instruction case couvrant elle-même.

+0

ouais, en effet c'est ce que j'avais en tête, au cas où être nécessaire de le mettre en œuvre moi-même .... – Ichthyo