ChatGPT解决这个技术问题 Extra ChatGPT

在 Scala 的模式匹配系统中使用比较运算符

是否可以使用 Scala 中的模式匹配系统进行比较?例如:

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

第二个 case 语句是非法的,但我希望能够指定“当 a 大于时”。

这也可用于检查函数的计算结果是否为真,例如 case x if x.size > 2 => ...
要理解的重要一点是 => 运算符左侧的“模式”确实是“模式”。您拥有的第一个 case 表达式中的 10 不是整数文字。因此,您不能在左侧执行操作(例如 > 检查或说函数应用程序 isOdd(_))。

B
Ben James

您可以在模式之后添加一个守卫,即一个 if 和一个布尔表达式:

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

编辑:请注意,这与在 => 之后放置 if 相比表面上有所不同,因为如果守卫不正确,则模式 不会 匹配。


Ben,很好的答案,它确实说明了模式保护的重要性。
s
seh

作为对问题精神的非回答,它询问如何将谓词合并到匹配子句中,在这种情况下,谓词可以在 match 之前被分解:

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

现在,the documentation for scala.math.Ordering.compare(T, T) 只承诺不相等的结果将大于小于零。 Java 的 Comparable#compareTo(T) 的指定与 Scala 的类似。就像 Scala 的 current implementation 所做的那样,分别对正值和负值使用 1 和 -1 是一种惯例,但是如果没有从底层改变实现的风险,就不能做出这样的假设。


我不确定您是否建议将此作为真正的解决方案,但我强烈建议您反对任何依赖于未记录的约定或假设的事情。
确切地。这就是为什么我写了“一个人不能在没有风险的情况下做出这样的假设”,并将我的回答定性为“不回答”。考虑为什么 compare()compareTo() 不指定 0、1 和 -1 作为它们的共同域是很有趣的。
Math.signum(n compare 10) 将保证 -1、0 或 1。
今天早上,我确认在写下我的原始答案将近六年后,即使有问题的实现从一种类型转移到另一种类型,Scala 仍然保持返回 -1、0 或 1 的注意行为。
一个有效的答案,但我个人不喜欢这个。很容易忘记 0,1 和 -1 的含义。
v
vergenzt

在我看来,一个比添加警卫更具可读性的解决方案:

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

笔记:

Ordered.compare 如果小于该整数,则返回一个负整数,如果大于该整数,则返回正整数,如果相等则返回 0。

Int.signum 将比较的输出压缩为 -1 表示负数(小于 10)、1 表示正数(大于 10)或 0 表示零(等于 10)。


S
Sergii Zhuravskyi

尽管以上和以下所有答案都完美地回答了原始问题,但可以在文档 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) 语句一起使用。

我希望这可以帮助像我这样的人。


I
Ireina

Scala 的模式匹配允许您定义自己的提取器。在这种情况下,您可以简单地定义一个新的提取器:

class GreaterThan(n: Int) {
  def unapply(i: Int) = i > n
}

val GreaterThan10 = GreaterThan(10)

a match {
  case 10 => ???
  case GreaterThan10() => ???
  case _ => ???
}

或者只使用模式防护。