【问题标题】:How to systematically avoid unsafe pattern matching in Scala?如何在 Scala 中系统地避免不安全的模式匹配?
【发布时间】:2012-01-18 14:20:30
【问题描述】:

考虑以下损坏的函数:

def sum (list : Seq[Int]) : Int = list match {
  case Nil => 0
  case head :: tail => head + sum(tail)
}

这里,该函数应该使用List[Int],但被重构为接受Seq[Int],因此在编译器没有注意到的情况下被破坏。

Scala 不完整的模式匹配检测中的这个巨大漏洞使它几乎毫无用处。

我希望有一种方法可以系统地检测此类问题。具体来说,我希望编译器在每个 instanceof-guided 模式匹配时发出错误/警告,即我只想允许在密封层次结构和自定义匹配器上进行模式匹配。

是否存在用于对模式匹配安全性进行保守(而不是任意)检查的编译器选项/插件?

【问题讨论】:

  • 我也经常将这个匹配示例与List 一起使用。在这种情况下,我的建议是使用list.toList match ...(因为您事先知道稍后可能会重构一些代码(可能不是这种方法),而匹配案例仅适用于List),然后您可以重构该方法Seq 的参数没有损坏的代码。

标签: scala pattern-matching non-exhaustive-patterns


【解决方案1】:

看看 M. Odersky 的 this answer

总结

检查非密封层次结构的匹配是可行的,不是微不足道的,也没有(尚未)实施。

【讨论】:

  • 这没有抓住重点。我不要求编译器无所不知甚至聪明。我只是希望检查变得保守,这意味着在“安全/不安全/未知”分析中,只有第一个会在没有警告的情况下被接受。
【解决方案2】:

Nil:: 显然是构造List 的方法,但并非所有Sequences 都恰好是Lists,所以人们会期望Scala 类型检查器将该程序视为错误类型而拒绝.对吧?

错了。试试这个,你就会明白我的意思了:

def sum (list : Seq[Int]) : Int = list match {
  case Nil => 0
  case head :: tail => head + sum(tail)
  case _ => -1
}

> sum(Array(1,2,3).toSeq)
res1: Int = -1
> sum(List(1,2,3))
res2: Int = 6

所以你看,一些 Sequences 可能可以用Nil::解构,所以那些可以的,会的。那些不能的将失败模式匹配并继续前进,尝试下一个匹配。 Nil:: 足以涵盖List 的所有可能性,但不适用于Seq。这里需要在子类型化、便利性和类型安全性之间进行权衡。目前的解决方案是:重构时要更加小心。

【讨论】:

    猜你喜欢
    • 2019-06-27
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多