Використання операторів порівняння в системі зіставлення шаблонів 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 (_)) зліва.
Устаман Сангат

Відповіді:


292

Ви можете додати охорону, тобто ifвираз і булевий вираз після шаблону:

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
Я не впевнений, чи пропонуєте ви це як реальне рішення, але я настійно рекомендую проти всього, що спирається на незадокументовану конвенцію чи припущення.
Бен Джеймс

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 (якщо).

Я сподіваюся, що це допомагає комусь, як я.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.