什么时候应该使用.empty而不是单例空实例?

时间:2014-07-17 14:33:19

标签: scala collections types

在Scala中使用集合时,通常需要将集合的空实例用于基本案例。因为默认的空实例使用类型参数Nothing扩展集合类型类,所以它有时会使类型推断无法直接使用它们。例如:

scala> List(1, 2, 3).foldLeft(Nil)((x, y) => x :+ y.toString())
<console>:8: error: type mismatch;
 found   : List[String]
 required: scala.collection.immutable.Nil.type
              List(1, 2, 3).foldLeft(Nil)((x, y) => x :+ y.toString())

                                                  ^

失败,但以下两项更正成功:

scala> List(1, 2, 3).foldLeft(Nil: List[String])((x, y) => x :+ y.toString())
res9: List[String] = List(1, 2, 3)

scala> List(1, 2, 3).foldLeft(List.empty[String])((x, y) => x :+ y.toString())
res10: List[String] = List(1, 2, 3)

我遇到类似困境的另一个地方是定义默认参数。这些是我能想到的唯一例子,但我知道我见过其他人。提供正确类型提示的一种方法通常优于另一种方法吗?是否存在各自有利的地方?

1 个答案:

答案 0 :(得分:1)

我倾向于使用Nil(或None)结合告诉类型参数化方法类型(如Kigyo)给出的特定用例。虽然我认为使用显式类型注释对于给定的用例同样可行。但我认为有些用例需要坚持使用.empty,例如,如果你试图在Nil: List[String]上调用一个方法,首先必须将其包装在大括号中,这样就可以了 2个额外的角色!!

现在使用.empty的另一个参数是与整个集合层次结构的一致性。例如,您无法执行Nil: Set[String]而无法执行Nil: Option[String],但您可以执行Set.empty[String]Option.empty[String]。因此,除非您确定您的代码永远不会被重构到其他集合中,否则您应该使用.empty,因为它需要更少的faff来重构。此外,保持一致是一般的好吗? :)

公平地说我经常使用NilNone因为我经常确定我永远不想使用Set或其他东西,事实上我会说最好使用Nil当你真正确定你只会处理列表时,因为它告诉读者代码“我真的真的在这里处理列表”。

最后,你可以用.empty和鸭子打字做一些很酷的东西,看一下这个简单的例子:

def printEmptyThing[K[_], T <: {def empty[A] : K[A]}](c: T): Unit = 
  println("thing = " + c.empty[String])

printEmptyThing[List, List.type](List)
printEmptyThing[Option, Option.type](Option)
printEmptyThing[Set, Set.type](Set)

将打印:

> thing = List()

> thing = None

> thing = Set()