Menggunakan operator pembanding dalam sistem pencocokan pola Scala

148

Apakah mungkin untuk mencocokkan perbandingan menggunakan sistem pencocokan pola di Scala? Sebagai contoh:

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

Pernyataan kasus kedua adalah ilegal, tetapi saya ingin dapat menentukan "kapan a lebih besar dari".

Cocok dengan Teorema
sumber
1
Ini juga dapat digunakan untuk memeriksa apakah suatu fungsi mengevaluasi true, misalnyacase x if x.size > 2 => ...
tstenner
2
Yang penting untuk dipahami adalah bahwa "pola" di sebelah kiri operator => memang "pola". 10 dalam ekspresi kasus pertama yang Anda miliki BUKAN integer literal. Jadi, Anda tidak dapat melakukan operasi (seperti> memeriksa atau mengatakan aplikasi fungsi isOdd (_)) di sebelah kiri.
Ustaman Sangat

Jawaban:

292

Anda bisa menambahkan penjaga, yaitu ifekspresi a dan boolean setelah pola:

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

Edit: Catatan bahwa ini adalah lebih dari dangkal yang berbeda untuk meletakkan sebuah if setelah itu =>, karena pola tidak akan cocok jika penjaga tidak benar.

Ben James
sumber
3
Ben, jawaban yang bagus, itu benar-benar menggambarkan pentingnya penjaga pola.
JeffV
32

Sebagai jawaban terhadap semangat pertanyaan, yang bertanya bagaimana memasukkan predikat ke dalam klausa pertandingan, dalam hal ini predikat dapat diperhitungkan sebelum match:

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

Sekarang, dokumentasi untukscala.math.Ordering.compare(T, T) janji hanya bahwa hasil yang tidak sama akan lebih besar dari atau kurang dari nol . Java Comparable#compareTo(T)dispesifikasikan mirip dengan Scala. Kebetulan konvensional menggunakan 1 dan -1 untuk nilai-nilai positif dan negatif, masing-masing, seperti implementasi Scala saat ini, tetapi kita tidak dapat membuat asumsi seperti itu tanpa risiko implementasi berubah dari bawah.

seh
sumber
5
Saya tidak yakin apakah Anda menyarankan ini sebagai solusi nyata, tetapi saya akan sangat menyarankan terhadap apa pun yang bergantung pada konvensi atau asumsi yang tidak berdokumen.
Ben James
1
Persis. Itu sebabnya saya menulis "seseorang tidak dapat membuat asumsi seperti itu tanpa risiko", dan memenuhi syarat jawaban saya sebagai "tidak dijawab". Sangat menarik untuk mempertimbangkan mengapa compare() dan compareTo()tidak menentukan 0, 1, dan -1 sebagai kodomain mereka.
seh
4
Math.signum (n bandingkan 10) akan menjamin -1, 0 atau 1.
richj
1
Pagi ini saya mengkonfirmasi bahwa hampir enam tahun setelah menulis jawaban asli saya, meskipun implementasi yang dimaksud berpindah dari satu jenis ke yang lain, Scala masih mempertahankan perilaku mencatat pengembalian -1, 0, atau 1.
seh
2
Jawaban yang valid, tetapi secara pribadi saya tidak suka ini. Terlalu mudah untuk melupakan apa artinya 0,1, dan -1 yang seharusnya.
DanGordon
21

Solusi yang menurut saya jauh lebih mudah dibaca daripada menambahkan penjaga:

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

Catatan:

  • Ordered.comparemengembalikan bilangan bulat negatif jika ini kurang dari itu, positif jika lebih besar, dan 0jika sama.
  • Int.signumkompres output dari compareke -1untuk angka negatif (kurang dari 10), 1untuk positif (lebih besar dari 10), atau 0untuk nol (sama dengan 10).
Vergenzt
sumber
1

Sementara semua jawaban di atas dan di bawah dengan sempurna menjawab pertanyaan asli, beberapa informasi tambahan dapat ditemukan dalam dokumentasi https://docs.scala-lang.org/tour/pattern-matching.html , mereka tidak cocok dengan kasus saya tetapi karena jawaban stackoverflow ini adalah saran pertama di Google saya ingin memposting jawaban saya yang merupakan kasus sudut pertanyaan di atas.
Pertanyaanku adalah:

  • Bagaimana cara menggunakan penjaga dalam ekspresi kecocokan dengan argumen fungsi?

Yang dapat diparafrasekan:

  • Bagaimana cara menggunakan pernyataan if dalam pencocokan ekspresi dengan argumen fungsi?

Jawabannya adalah contoh kode di bawah ini:

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

tautan ke scala fiddle: https://scalafiddle.io/sf/G37THif/2 karena Anda dapat melihat case xs if n <= 0 => xspernyataan tersebut dapat menggunakan n (argumen fungsi) dengan pernyataan penjaga (jika).

Saya harap ini membantu orang seperti saya.

Sergii Zhuravskyi
sumber