Verwenden von Vergleichsoperatoren in Scalas Mustervergleichssystem

148

Ist es möglich, einen Vergleich mit dem Mustervergleichssystem in Scala durchzuführen? Beispielsweise:

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

Die zweite case-Anweisung ist illegal, aber ich möchte angeben können, "wann a größer als" ist.

Passend zum Satz
quelle
1
Dies kann auch verwendet werden, um zu überprüfen, ob eine Funktion als wahr ausgewertet wird, z. B.case x if x.size > 2 => ...
tstenner
2
Es ist wichtig zu verstehen, dass die "Muster" links vom Operator => tatsächlich "Muster" sind. Die 10 im ersten Fall, den Sie haben, ist NICHT das ganzzahlige Literal. Sie können also keine Operationen (wie> Überprüfen oder Sagen der Funktionsanwendung isOdd (_)) auf der linken Seite ausführen.
Ustaman Sangat

Antworten:

292

Sie können ifnach dem Muster einen Schutz hinzufügen, dh einen und einen booleschen Ausdruck:

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

Bearbeiten: Beachten Sie, dass dies mehr als nur oberflächlich anders ist als das Setzen eines if Nach dem =>, da ein Muster nicht übereinstimmt, wenn der Schutz nicht wahr ist.

Ben James
quelle
3
Ben, gute Antwort, es zeigt wirklich, wie wichtig Pattern Guard ist.
JeffV
32

Als Nichtantwort auf den Geist der Frage, der fragte, wie Prädikate in eine Übereinstimmungsklausel aufgenommen werden sollen, kann das Prädikat in diesem Fall vor dem match:

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

Nun verspricht die Dokumentationscala.math.Ordering.compare(T, T) nur, dass die ungleichen Ergebnisse größer oder kleiner als Null sein werden . Java Comparable#compareTo(T)wird ähnlich wie Scala spezifiziert. Es ist üblich, 1 und -1 für die positiven bzw. negativen Werte zu verwenden, wie dies bei der aktuellen Implementierung von Scala der Fall ist, aber man kann eine solche Annahme nicht treffen, ohne dass das Risiko besteht, dass sich die Implementierung von unten ändert.

seh
quelle
5
Ich bin mir nicht sicher, ob Sie dies als echte Lösung vorschlagen, aber ich würde dringend empfehlen, alles zu unterbinden, was auf einer undokumentierten Konvention oder Annahme beruht.
Ben James
1
Genau. Deshalb schrieb ich "man kann eine solche Annahme nicht ohne Risiko machen" und qualifizierte meine Antwort als "Nichtantwort". Es ist interessant zu überlegen, warum compare() und compareTo()geben Sie nicht 0, 1 und -1 als Codomäne an.
seh
4
Math.signum (n vergleiche 10) würde -1, 0 oder 1 garantieren.
richj
1
Heute Morgen habe ich bestätigt, dass Scala fast sechs Jahre nach dem Schreiben meiner ursprünglichen Antwort, obwohl die fragliche Implementierung von einem Typ zu einem anderen verschoben wurde, immer noch das festgestellte Verhalten der Rückgabe von -1, 0 oder 1 beibehält.
seh
2
Eine gültige Antwort, aber ich persönlich mag das nicht. Es ist zu leicht zu vergessen, was 0,1 und -1 bedeuten sollen.
DanGordon
21

Eine Lösung, die meiner Meinung nach viel besser lesbar ist als das Hinzufügen von Wachen:

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

Anmerkungen:

  • Ordered.compareGibt eine negative Ganzzahl zurück, wenn diese kleiner als diese ist, positiv, wenn größer und 0wenn gleich.
  • Int.signumKomprimiert die Ausgabe von comparebis -1für eine negative Zahl (kleiner als 10), 1für eine positive Zahl ( größer als 10) oder 0für Null (gleich 10).
vergenzt
quelle
1

Alle oben genannten und nachstehenden Antworten beantworten die ursprüngliche Frage perfekt. Einige zusätzliche Informationen finden Sie in der Dokumentation https://docs.scala-lang.org/tour/pattern-matching.html . Sie passten jedoch nicht in meinen Fall Da diese Stackoverflow-Antwort jedoch der erste Vorschlag in Google ist, möchte ich meine Antwort veröffentlichen, die ein Eckfall der obigen Frage ist.
Meine Frage ist:

  • Wie verwende ich einen Guard im Match-Ausdruck mit einem Argument einer Funktion?

Was umschrieben werden kann:

  • Wie verwende ich eine if-Anweisung im Übereinstimmungsausdruck mit einem Argument einer Funktion?

Die Antwort ist das folgende Codebeispiel:

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

Link zur Scala Geige: https://scalafiddle.io/sf/G37THif/2 Wie Sie sehen können, kann die case xs if n <= 0 => xsAnweisung n (Argument einer Funktion) mit der guard (if) -Anweisung verwenden.

Ich hoffe das hilft jemandem wie mir.

Sergii Zhuravskyi
quelle