如何防止这种bug - 模式匹配和Nil

时间:2012-02-19 09:09:11

标签: scala

再次模式匹配列表时,可以使用Nil检查空列表。但是,如果基础类型是Iterable,您仍然可以检查Nil,它将为空集等中断...请参阅以下REPL会话:

scala> val l: Iterable[Int] = List()
l: Iterable[Int] = List()

scala> l match {
     | case Nil => 1
     | case _ => 2
     | }
res0: Int = 1

scala> val l: Iterable[Int] = Set() 
l: Iterable[Int] = Set()

scala> l match {
     | case Nil => 1
     | case _ => 2
     | }
res2: Int = 2

问题是 - 我该如何防止这类问题?显然,如果l是类型List,那就不是bug。如果l的类型为Set,则不会编译。但是,如果我们有一个具有列表的类,定义一个模式以这种方式匹配的函数,然后有人改变该类以采用通用迭代呢?这种Nil vs. _模式一般来说是个坏主意吗?

3 个答案:

答案 0 :(得分:12)

一种可能性是使用警卫:

scala> val xs: Iterable[Int] = Set()
xs: Iterable[Int] = Set()

scala> xs match { case xs if xs.isEmpty => 1 case _ => 2 }
res0: Int = 1

另一种方法是使用if-else-expression(如果你只有一个或两个条件要检查,效果最好):

scala> if (xs.isEmpty) 1 else 2
res1: Int = 1

答案 1 :(得分:8)

将scrutinee转换为列表以消除疑虑。

l.toList match {
  case Nil => 1
  case xs  => 2
}

答案 2 :(得分:1)

这是另一种选择(双关语):

scala> val l: Iterable[Int] = List()
l: Iterable[Int] = List()

scala> l.headOption match { case None => 1; case Some(h) => 2 }
res0: Int = 1

这适用于模式匹配以便在热门head中获得List() match { case h :: t => ... }的情况,但它不是列表,而是Iterable {{1将失败

我添加了这个答案,因为我认为对一个集合进行模式匹配是很常见的,否则你只需要查看::