Utilizzo degli operatori di confronto nel sistema di corrispondenza dei modelli di Scala


148

È possibile abbinare un confronto utilizzando il sistema di corrispondenza dei modelli in Scala? Per esempio:

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

La seconda dichiarazione del caso è illegale, ma vorrei essere in grado di specificare "quando a è maggiore di".


1
Questo può anche essere usato per verificare se una funzione viene valutata come vera, ad esempiocase x if x.size > 2 => ...
tstenner

2
La cosa importante da capire è che gli "schemi" a sinistra dell'operatore => sono effettivamente "schemi". Il 10 nell'espressione del primo caso che hai NON è il valore intero letterale. Pertanto, non è possibile eseguire operazioni (come> controllare o dire che l'applicazione funzione isOdd (_)) a sinistra.
Ustaman Sangat,

Risposte:


292

È possibile aggiungere una guardia, ovvero ifun'espressione booleana e dopo il modello:

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

Modifica: Nota che questo è più che superficialmente diverso dal mettere un if after the =>, perché un pattern non corrisponderà se la guardia non è vera.


3
Ben, buona risposta, illustra davvero l'importanza della protezione del modello.
JeffV,

32

Come non risposta allo spirito della domanda, che ha chiesto come incorporare i predicati in una clausola di abbinamento, in questo caso il predicato può essere preso in considerazione prima del match :

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

Ora, la documentazione perscala.math.Ordering.compare(T, T) promette solo che i risultati non uguali saranno maggiori o minori di zero . Java Comparable#compareTo(T)è specificato in modo simile a quello di Scala. Sembra essere convenzionale usare 1 e -1 per i valori positivi e negativi, rispettivamente, come fa l' implementazione attuale di Scala , ma non si può fare un tale presupposto senza un certo rischio che l'implementazione cambi da sotto.


5
Non sono sicuro che tu stia suggerendo questo come una soluzione reale, ma raccomanderei caldamente tutto ciò che si basa su una convenzione o assunzione non documentata.
Ben James,

1
Esattamente. Ecco perché ho scritto "non si può fare una simile ipotesi senza un certo rischio" e ho qualificato la mia risposta come "non-risposta". È interessante considerare perché compare() e compareTo()non specificare 0, 1 e -1 come loro codice.
seh,

4
Math.signum (n confrontare 10) garantirebbe -1, 0 o 1.
richj

1
Stamattina ho confermato che quasi sei anni dopo aver scritto la mia risposta originale, anche se l'implementazione in questione è passata da un tipo a un altro, Scala mantiene ancora quel noto comportamento di ritorno -1, 0 o 1.
seh

2
Una risposta valida, ma personalmente non mi piace. È troppo facile dimenticare cosa dovrebbero significare 0,1 e -1.
DanGordon,

21

Una soluzione che secondo me è molto più leggibile dell'aggiunta di protezioni:

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

Appunti:

  • Ordered.comparerestituisce un numero intero negativo se questo è inferiore a quello, positivo se maggiore e 0se uguale.
  • Int.signumcomprime l'uscita da comparea -1per un numero negativo (inferiore a 10), 1per positivo (maggiore di 10) o 0per zero (uguale a 10).

1

Mentre tutte le risposte precedenti e qui sotto rispondono perfettamente alla domanda originale, alcune informazioni aggiuntive possono essere trovate nella documentazione https://docs.scala-lang.org/tour/pattern-matching.html , ma non si adattavano al mio caso ma poiché questa risposta StackOverflow è il primo suggerimento in Google, vorrei pubblicare la mia risposta, che è un caso d'angolo della domanda precedente.
La mia domanda è:

  • Come usare una guardia nell'espressione di corrispondenza con un argomento di una funzione?

Che può essere parafrasato:

  • Come usare un'istruzione if nell'espressione di corrispondenza con un argomento di una funzione?

La risposta è il seguente esempio di codice:

    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 a scala fiddle: https://scalafiddle.io/sf/G37THif/2 come puoi vederecase xs if n <= 0 => xs istruzione è in grado di usare n (argomento di una funzione) con l'istruzione guard (if).

Spero che questo aiuti qualcuno come me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.