Utilisation des opérateurs de comparaison dans le système de correspondance de modèles de Scala


148

Est-il possible de faire une correspondance sur une comparaison en utilisant le système de correspondance de modèles dans Scala? Par exemple:

a match {
    case 10 => println("ten")
    case _ > 10 => println("greater than ten")
    case _ => println("less than ten")
}

La deuxième déclaration de cas est illégale, mais j'aimerais pouvoir spécifier "quand a est supérieur à".


1
Cela peut également être utilisé pour vérifier si une fonction est évaluée à vrai, par exemplecase x if x.size > 2 => ...
tstenner

2
La chose importante à comprendre est que les "motifs" à gauche de l'opérateur => sont en effet des "motifs". Le 10 dans le premier cas d'expression que vous avez n'est PAS le littéral entier. Ainsi, vous ne pouvez pas effectuer d'opérations (comme> vérifier ou dire l'application de fonction isOdd (_)) sur la gauche.
Ustaman Sangat

Réponses:


292

Vous pouvez ajouter une garde, c'est-à-dire une ifet une expression booléenne après le motif:

a match {
    case 10 => println("ten")
    case x if x > 10 => println("greater than ten")
    case _ => println("less than ten")
}

Edit: Notez que c'est plus que superficiellement différent de mettre un if après le =>, car un motif ne correspondra pas si la garde n'est pas vraie.


3
Ben, bonne réponse, cela illustre vraiment l'importance du patron de garde.
JeffV

32

En tant que non-réponse à l'esprit de la question, qui demandait comment incorporer des prédicats dans une clause de correspondance, dans ce cas, le prédicat peut être pris en compte avant match:

def assess(n: Int) {
  println(
    n compare 10 match {
      case 0 => "ten"
      case 1 => "greater than ten"
      case -1 => "less than ten"
    })
}

Maintenant, la documentation pour lesscala.math.Ordering.compare(T, T) promesses seulement que les résultats non égaux seront supérieurs ou inférieurs à zéro . Java Comparable#compareTo(T)est spécifié de la même manière que Scala. Il se trouve qu'il est conventionnel d'utiliser 1 et -1 pour les valeurs positives et négatives, respectivement, comme le fait l'implémentation actuelle de Scala , mais on ne peut pas faire une telle hypothèse sans un risque que l'implémentation change de dessous.


5
Je ne sais pas si vous suggérez cela comme une vraie solution, mais je vous déconseille fortement tout ce qui repose sur une convention ou une hypothèse non documentée.
Ben James

1
Exactement. C'est pourquoi j'ai écrit "on ne peut pas faire une telle hypothèse sans un certain risque", et j'ai qualifié ma réponse de "non-réponse". Il est intéressant de considérer pourquoi compare() et de compareTo()ne pas spécifier 0, 1 et -1 comme codomaine.
seh

4
Math.signum (n compare 10) garantirait -1, 0 ou 1.
richj

1
Ce matin, j'ai confirmé que près de six ans après avoir écrit ma réponse originale, même si l'implémentation en question est passée d'un type à un autre, Scala maintient toujours ce comportement noté de retour de -1, 0 ou 1.
seh

2
Une réponse valable, mais personnellement je n'aime pas ça. Il est trop facile d'oublier ce que 0,1 et -1 sont censés signifier.
DanGordon

21

Une solution qui à mon avis est bien plus lisible que l'ajout de gardes:

(n compare 10).signum match {
    case -1 => "less than ten"
    case  0 => "ten"
    case  1 => "greater than ten"
}

Remarques:

  • Ordered.comparerenvoie un entier négatif s'il est inférieur à cela, positif s'il est supérieur et 0s'il est égal.
  • Int.signumcompresse la sortie de compareà -1pour un nombre négatif (inférieur à 10), 1pour positif (supérieur à 10) ou 0pour zéro (égal à 10).

1

Bien que toutes les réponses ci-dessus et ci-dessous répondent parfaitement à la question d'origine, des informations supplémentaires peuvent être trouvées dans la documentation https://docs.scala-lang.org/tour/pattern-matching.html , elles ne correspondaient pas à mon cas mais parce que cette réponse stackoverflow est la première suggestion de Google, je voudrais publier ma réponse qui est un cas secondaire de la question ci-dessus.
Ma question est:

  • Comment utiliser une garde dans une expression de correspondance avec un argument d'une fonction?

Ce qui peut être paraphrasé:

  • Comment utiliser une instruction if dans une expression de correspondance avec un argument d'une fonction?

La réponse est l'exemple de code ci-dessous:

    def drop[A](l: List[A], n: Int): List[A] = l match {
      case Nil => sys.error("drop on empty list")
      case xs if n <= 0 => xs
      case _ :: xs => drop(xs, n-1)
    }

lien vers scala fiddle: https://scalafiddle.io/sf/G37THif/2 comme vous pouvez le voir, l' case xs if n <= 0 => xsinstruction est capable d'utiliser n (argument d'une fonction) avec l'instruction guard (if).

J'espère que cela aide quelqu'un comme moi.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.