Sử dụng các toán tử so sánh trong hệ thống khớp mẫu của Scala


148

Có thể so khớp trên một so sánh bằng cách sử dụng hệ thống khớp mẫu trong Scala không? Ví dụ:

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

Tuyên bố trường hợp thứ hai là bất hợp pháp, nhưng tôi muốn có thể chỉ định "khi a lớn hơn".


1
Đây cũng có thể được sử dụng để kiểm tra xem một hàm trả về true, ví dụcase x if x.size > 2 => ...
tstenner

2
Điều quan trọng cần hiểu là "các mẫu" ở bên trái của toán tử => thực sự là "các mẫu". Số 10 trong biểu thức trường hợp đầu tiên bạn có KHÔNG phải là số nguyên. Vì vậy, bạn không thể thực hiện các thao tác (như> kiểm tra hoặc nói ứng dụng chức năng làOdd (_)) ở bên trái.
Ustaman Sangat

Câu trả lời:


292

Bạn có thể thêm một bảo vệ, tức là một ifbiểu thức boolean sau mẫu:

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

Chỉnh sửa: Lưu ý rằng đây là hơn một cách hời hợt khác nhau để chấm if sau các =>, bởi vì một mô hình sẽ không phù hợp nếu nhân viên bảo vệ là không đúng sự thật.


3
Ben, câu trả lời tốt, nó thực sự minh họa tầm quan trọng của bảo vệ mẫu.
JeffV

32

Là một câu trả lời không phù hợp với tinh thần của câu hỏi, đã hỏi làm thế nào để kết hợp các vị từ vào một mệnh đề khớp, trong trường hợp này, vị từ có thể được đưa ra trước match:

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

Bây giờ, tài liệu choscala.math.Ordering.compare(T, T) lời hứa chỉ rằng các kết quả không bằng nhau sẽ lớn hơn hoặc nhỏ hơn 0 . Java Comparable#compareTo(T)được chỉ định tương tự như Scala. Việc sử dụng 1 và -1 cho các giá trị dương và âm tương ứng là thông thường, như cách triển khai hiện tại của Scala , nhưng người ta không thể đưa ra một giả định như vậy mà không có rủi ro khi thực hiện thay đổi từ bên dưới.


5
Tôi không chắc liệu bạn có gợi ý đây là một giải pháp thực sự hay không, nhưng tôi thực sự khuyên bạn nên chống lại bất cứ điều gì liên quan đến một quy ước hoặc giả định không có giấy tờ.
Ben James

1
Chính xác. Đó là lý do tại sao tôi đã viết "người ta không thể đưa ra một giả định như vậy mà không có rủi ro" và đánh giá câu trả lời của tôi là "không trả lời". Thật thú vị khi xem xét lý do compare()compareTo()không chỉ định 0, 1 và -1 làm tên miền của họ.
seh

4
Math.signum (n so sánh 10) sẽ đảm bảo -1, 0 hoặc 1.
richj

1
Sáng nay tôi đã xác nhận rằng gần sáu năm sau khi viết câu trả lời ban đầu của mình, mặc dù việc triển khai trong câu hỏi đã chuyển từ loại này sang loại khác, Scala vẫn duy trì hành vi được ghi nhận là trả về -1, 0 hoặc 1.
seh

2
Một câu trả lời hợp lệ, nhưng cá nhân tôi không thích điều này. Thật quá dễ dàng để quên 0,1 và -1 nghĩa là gì.
DanGordon

21

Một giải pháp mà theo tôi là dễ đọc hơn nhiều so với việc thêm lính canh:

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

Ghi chú:

  • Ordered.comparetrả về một số nguyên âm nếu giá trị này nhỏ hơn số đó, dương nếu lớn hơn và 0nếu bằng nhau.
  • Int.signumnén đầu ra từ compaređến -1cho một số âm (nhỏ hơn 10), 1cho dương (lớn hơn 10) hoặc 0bằng 0 (bằng 10).

1

Mặc dù tất cả các câu trả lời trên và dưới đây trả lời hoàn hảo câu hỏi ban đầu, một số thông tin bổ sung có thể được tìm thấy trong tài liệu https://docs.scala-lang.org/tour/potype-matching.html , chúng không phù hợp với trường hợp của tôi nhưng vì câu trả lời stackoverflow này là gợi ý đầu tiên trong Google nên tôi muốn đăng câu trả lời của mình, đây là một trường hợp góc của câu hỏi ở trên.
Câu hỏi của tôi là:

  • Làm thế nào để sử dụng một bộ bảo vệ trong biểu thức khớp với một đối số của hàm?

Mà có thể được diễn giải:

  • Làm thế nào để sử dụng một câu lệnh if trong biểu thức khớp với một đối số của hàm?

Câu trả lời là ví dụ mã dưới đây:

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

liên kết đến scala fiddle: https://scalafiddle.io/sf/G37THif/2 vì bạn có thể thấy case xs if n <= 0 => xscâu lệnh có thể sử dụng n (đối số của hàm) với câu lệnh Guard (if).

Tôi hy vọng điều này sẽ giúp một người như tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.