Использование операторов сравнения в системе сопоставления с образцом Scala

148

Можно ли сопоставить сравнение с помощью системы сопоставления с образцом в Scala? Например:

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

Второе утверждение case недопустимо, но я хотел бы иметь возможность указать «когда a больше чем».

BefittingTheorem
источник
1
Это также может быть использовано для проверки того, оценивает ли функция значение true, напримерcase x if x.size > 2 => ...
tstenner
2
Важно понимать, что «шаблоны» слева от оператора => действительно являются «шаблонами». 10 в первом выражении case НЕ является целочисленным литералом. Таким образом, вы не можете выполнять операции (например,> проверить или сказать, что приложение функции 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 , но такое предположение невозможно сделать без некоторого риска того, что реализация изменится снизу.

SEH
источник
5
Я не уверен, предлагаете ли вы это как реальное решение, но я настоятельно рекомендую против всего, что основано на недокументированном соглашении или предположении.
Бен Джеймс
1
Именно. Вот почему я написал «никто не может сделать такое предположение без некоторого риска», и квалифицировал мой ответ как «не ответ». Интересно рассмотреть причину compare() и compareTo()не указывать 0, 1 и -1 в качестве своего кодомена.
SEH
4
Math.signum (n сравните 10) гарантирует -1, 0 или 1.
richj
1
Этим утром я подтвердил , что почти шесть лет после того, как писать свой оригинальный ответ, даже если реализация в вопросе перешла от одного типа к другому, Scala по- прежнему утверждает , что отмечено поведение возвращающей -1, 0 или 1.
SEH
2
Действительный ответ, но лично мне это не нравится. Слишком легко забыть, что должны означать 0,1 и -1.
ДанГордон
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).
vergenzt
источник
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)
    }

ссылка на Scala Fiddle: https://scalafiddle.io/sf/G37THif/2, как вы можете видетьcase xs if n <= 0 => xs оператор может использовать n (аргумент функции) с оператором guard (if).

Я надеюсь, что это помогает кому-то, как я.

Сергей Журавский
источник