การใช้ตัวดำเนินการเปรียบเทียบในระบบจับคู่รูปแบบของ Scala


148

เป็นไปได้หรือไม่ที่จะเปรียบเทียบในการเปรียบเทียบโดยใช้ระบบจับคู่รูปแบบใน Scala ตัวอย่างเช่น:

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

คำสั่งกรณีที่สองนั้นผิดกฎหมาย แต่ฉันต้องการระบุ "เมื่อ a มากกว่า"


1
นอกจากนี้ยังสามารถใช้เพื่อตรวจสอบว่าฟังก์ชันประเมินค่าเป็นจริงหรือไม่เช่นcase x if x.size > 2 => ...
tstenner

2
สิ่งสำคัญที่ต้องเข้าใจคือ "รูปแบบ" ทางด้านซ้ายของ => ตัวดำเนินการเป็น "รูปแบบ" แน่นอน 10 ในนิพจน์กรณีแรกที่คุณมีไม่ใช่ตัวอักษรจำนวนเต็ม ดังนั้นคุณไม่สามารถดำเนินการได้ (เช่น> ตรวจสอบหรือพูดแอปพลิเคชันฟังก์ชั่น isOdd (_)) ทางซ้าย
Ustaman Sangat

คำตอบ:


292

คุณสามารถเพิ่มตัวป้องกันได้เช่น an ifและ a นิพจน์บูลีนหลังรูปแบบ:

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

แก้ไข: โปรดทราบว่านี้เป็นมากกว่าเผิน ๆ แตกต่างกันเพื่อวางif หลังจาก=>เพราะรูปแบบจะไม่ตรงถ้ายามไม่เป็นความจริง


3
เบ็นคำตอบที่ดีมันแสดงให้เห็นถึงความสำคัญของการป้องกันลวดลาย
JeffV

32

ในฐานะที่เป็นคำตอบที่ไม่ตอบคำถามของจิตวิญญาณซึ่งถามว่าจะรวมภาคเพรดิเคตลงในประโยคการแข่งขันได้อย่างไรในกรณีนี้คำกริยาสามารถแยกออกได้ก่อนmatch:

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

ตอนนี้เอกสารสำหรับscala.math.Ordering.compare(T, T)สัญญาเดียวที่ผลลัพธ์ที่ไม่เท่ากันจะมากกว่าหรือน้อยกว่าศูนย์ Java Comparable#compareTo(T)ถูกระบุเช่นเดียวกับ Scala มันเป็นเรื่องธรรมดาที่จะใช้ 1 และ -1 สำหรับค่าบวกและค่าลบตามลำดับขณะที่การดำเนินการปัจจุบันของ Scala ทำได้ แต่ไม่มีใครสามารถตั้งสมมติฐานดังกล่าวได้


5
ฉันไม่แน่ใจว่าคุณกำลังแนะนำสิ่งนี้เป็นวิธีการแก้ปัญหาจริงหรือไม่ แต่ฉันขอแนะนำอย่างยิ่งยวดต่อสิ่งที่ต้องอาศัยการประชุมหรือการสันนิษฐานที่ไม่มีเอกสาร
Ben James

1
เผง นั่นเป็นเหตุผลที่ฉันเขียนว่า "ไม่มีใครสามารถตั้งสมมติฐานได้โดยไม่มีความเสี่ยง" และทำให้คำตอบของฉันเป็น "ไม่ตอบ" เป็นเรื่องที่น่าสนใจที่จะพิจารณาว่าทำไม compare()และcompareTo()ไม่ระบุ 0, 1 และ -1 เป็นโคโดเมน
seh

4
Math.signum (n เปรียบเทียบ 10) จะรับประกัน -1, 0 หรือ 1
richj

1
เมื่อเช้านี้ฉันยืนยันว่าเกือบหกปีหลังจากเขียนคำตอบดั้งเดิมของฉันแม้ว่าการดำเนินการที่เป็นปัญหาจะเปลี่ยนจากประเภทหนึ่งไปเป็นประเภทอื่นสกาล่ายังคงรักษาพฤติกรรมของการกลับมาที่ -1, 0 หรือ 1
seh

2
คำตอบที่ถูกต้อง แต่โดยส่วนตัวแล้วฉันไม่ชอบสิ่งนี้ มันง่ายเกินไปที่จะลืมว่า 0,1 และ -1 ควรจะหมายถึงอะไร
DanGordon

21

วิธีแก้ปัญหาที่ในความคิดของฉันอ่านได้ง่ายกว่าการเพิ่มการ์ด:

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

หมายเหตุ:

  • Ordered.compareส่งคืนเลขจำนวนเต็มลบหากนี่น้อยกว่านั้นบวกถ้ายิ่งใหญ่กว่าและ 0หากเท่ากัน
  • Int.signumบีบอัดเอาต์พุตจากcompareถึง-1เป็นจำนวนลบ (น้อยกว่า 10) 1สำหรับบวก (มากกว่า 10) หรือ0เป็นศูนย์ (เท่ากับ 10)

1

ในขณะที่คำตอบทั้งหมดข้างต้นและคำตอบการร้องอย่างสมบูรณ์ตอบคำถามเดิมอย่างสมบูรณ์ข้อมูลเพิ่มเติมบางอย่างสามารถพบได้ในเอกสารhttps://docs.scala-lang.org/tour/pattern-matching.htmlพวกเขาไม่พอดีในกรณีของฉัน แต่เนื่องจากคำตอบ stackoverflow นี้เป็นคำแนะนำแรกใน Google ฉันต้องการโพสต์คำตอบของฉันซึ่งเป็นกรณีมุมของคำถามข้างต้น
คำถามของฉันคือ:

  • วิธีการใช้ยามในการแสดงออกการแข่งขันกับการโต้แย้งของฟังก์ชั่นหรือไม่?

ซึ่งสามารถถอดความ:

  • วิธีการใช้คำสั่ง if ในนิพจน์จับคู่กับอาร์กิวเมนต์ของฟังก์ชัน?

คำตอบคือตัวอย่างรหัสด้านล่าง:

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

ลิงก์ไปยังซอสกาล่า: https://scalafiddle.io/sf/G37THif/2 ตามที่คุณเห็นcase xs if n <= 0 => xsคำสั่งนี้สามารถใช้ n (อาร์กิวเมนต์ของฟังก์ชัน) กับคำสั่ง Guard (ถ้า)

ฉันหวังว่านี่จะช่วยคนอย่างฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.