似乎Arrays的模式匹配器不会抱怨丢失的情况。
例如,如果我尝试从args
字符串数组中读取...
def main(args: Array[String]) {
val limit = args match {
case Array(x, _*) => { println("Running for " + x) ; x.toInt }
// case _ => 1000
}
}
...编译器是静默的,即使我没有匹配所有可能的Array情况(例如空的情况)。但是,如果我将数组转换为List ...
def main(args: Array[String]) {
val limit = args.toList match {
case x :: xs => { println("Running for " + x) ; x.toInt }
// case _ => 1000
}
}
...然后编译器捕获错误,并报告:
[warn] missedErrorCase.scala:38: match may not be exhaustive.
[warn] It would fail on the following input: Nil
[warn] val limit = args.toList match {
[warn] ^
[warn] one warning found
我是否遗漏了某些内容,或者这是Scala模式匹配逻辑中的错误?
答案 0 :(得分:6)
如果没有特殊套管Array
,编译器就不可能知道匹配并非详尽无遗。 unapplySeq
过于笼统。
考虑一个"非空序列的(非牵强)示例"类型。
class NonEmptySeq[A](val head: A, val tail: Seq[A]) {
def toIndexedSeq: IndexedSeq[A] = head +: tail.toIndexedSeq
}
object NonEmptySeq {
def unapplySeq[A](x: NonEmptySeq[A]): Option[IndexedSeq[A]] =
Some(x.toIndexedSeq)
}
def limit(args: NonEmptySeq[String]) =
args match { case NonEmptySeq(x, _*) => x.toInt }
这种情况下的匹配是详尽无遗的,因为取消应用NonEmptySeq
将始终产生至少一个值,但编译器无法看到。
请注意,如果您只是将Array
替换为List
,则会遇到同样的问题。此代码也不会产生任何警告:
def limit(args: List[String]) =
args match { case List(x, _*) => x.toInt }
匹配表达式x :: xs
是::(x, xs)
的糖。遗憾的是,::
类似乎从scaladoc中省略了,所以我不得不鼓励你看the source code。类定义看起来像这样(为了简单起见,我在这里对它进行了虚构化):
case class ::[A](head: A, tail: List[A]) extends List[A]
匹配表达式x :: xs
是指自动生成的::.unapply
方法,因为::
是一个案例类。
编译器知道List
有两种子类型(并且正好有两种,因为List
是密封的):
::
Nil
所以当你有
时def limit(args: List[String]) =
args match { case x :: xs => x.toInt }
模式匹配涵盖 ::
,但Nil
不是 - 因此警告。
答案 1 :(得分:0)
列表是scala中的sealed abstract class
。如果您使用.toSeq
代替.toList
,则不会收到警告,因为Seq只是trait
。 Scala使用此密封关键字来检查匹配语句是否详尽无遗。