此代码编译:
def wtf(arg: Any) = {
arg match {
case Nil => "Nil was passed to arg"
case List() => "List() was passed to arg"
case _ =>"otherwise"
}
}
Run Code Online (Sandbox Code Playgroud)
但是这个没有:
def wtf(arg: Any) = {
arg match {
case List() => "List() was passed to arg"
case Nil => "Nil was passed to arg"
case _ =>"otherwise"
}
}
Run Code Online (Sandbox Code Playgroud)
行 情况Nil => ...被标记为无法访问的代码.为什么,在第一种情况下,行案例List()=> ...没有标记相同的错误?
实际的答案需要理解一个不幸的实现细节,这花费了我很多时间来发现.
1)case List()调用一个提取器,在一般情况下不能进行穷举/不可达性检查,因为提取器调用任意函数.到目前为止,我们不能指望我们推翻停止问题.
2)回到编译器的"狂野西部"时代,如果"case List()"刚刚被翻译为"case Nil",那么确定模式匹配可以加速相当多(并且不会失去穷举性检查) "在早期的编译阶段,所以它会避免提取器.情况仍然如此,虽然它可以撤消,但很多人都被告知"case List()=>"非常好,我们不想突然对所有代码感到悲观.所以我只需要找出一条出路.
您可以通过在其他类中尝试使用经验来查看List是否具有特权.没有不可达性错误.
import scala.collection.immutable.IndexedSeq
val Empty: IndexedSeq[Nothing] = IndexedSeq()
def wtf1(arg: Any) = {
arg match {
case Empty => "Nil was passed to arg"
case IndexedSeq() => "IndexedSeq() was passed to arg"
case _ =>"otherwise"
}
}
def wtf2(arg: Any) = {
arg match {
case IndexedSeq() => "IndexedSeq() was passed to arg"
case Empty => "Nil was passed to arg"
case _ =>"otherwise"
}
}
Run Code Online (Sandbox Code Playgroud)
这种差异特别奇怪,因为Nil第二版中的案例代码肯定是无法访问的,因为我们可以看到我们是否从编译器中隐藏了一些内容:
def wtf(arg: Any) = {
arg match {
case List() => "List() was passed to arg"
case x => x match {
case Nil => "Nil was passed to arg"
case _ =>"otherwise"
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在wtf(Vector())将回归"Nil was passed to arg".这也似乎违反直觉,但它的字面因为模式匹配是在以下方面相等的值==,并且Vector() == Nil,但是Vector()提取模式不匹配List().
更简洁:
scala> (Vector(): Seq[_]) match { case List() => true; case Nil => false }
<console>:8: error: unreachable code
scala> (Vector(): Seq[_]) match { case List() => true; case x => x match { case Nil => false } }
res0: Boolean = false
Run Code Online (Sandbox Code Playgroud)
因此编译器的响应完全颠倒了:在"好"版本中第二种情况是无法访问的,而在"坏"版本中第二种情况完全正常.我已将此报告为错误(SI-5029).
Nil是一个扩展的对象List[Nothing].比更具体的List(),如果它出现后它没有达到List()的情况下表达.
虽然我认为上述情况或多或少都是正确的,但可能不是整个故事.
文章" 匹配带模式的对象"中有一些提示,但我没有看到明确的答案.
我怀疑对于命名常量和文字而言,对于不可达性的检测比对于构造函数模式更完全实现,并且List()被解释为构造函数模式(即使它是一个微不足道的模式),Nil而是一个命名常量.