Nil和List作为Scala中的case表达式

fer*_*ito 11 scala

此代码编译:

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()=> ...没有标记相同的错误?

psp*_*psp 9

实际的答案需要理解一个不幸的实现细节,这花费了我很多时间来发现.

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)


Tra*_*own 6

这种差异特别奇怪,因为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).

  • +1 - 你是对的.它看起来像一个bug. (2认同)

Don*_*oby 5

Nil是一个扩展的对象List[Nothing].比更具体的List(),如果它出现后它没有达到List()的情况下表达.

虽然我认为上述情况或多或少都是正确的,但可能不是整个故事.

文章" 匹配带模式的对象"中有一些提示,但我没有看到明确的答案.

我怀疑对于命名常量和文字而言,对于不可达性的检测比对于构造函数模式更完全实现,并且List()被解释为构造函数模式(即使它是一个微不足道的模式),Nil而是一个命名常量.