Scala - 数组上的模式匹配并不会针对丢失的情况发出警告

时间:2014-12-08 09:56:06

标签: scala pattern-matching

似乎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模式匹配逻辑中的错误?

2 个答案:

答案 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使用此密封关键字来检查匹配语句是否详尽无遗。