假设我有一个接受对象和列表的函数:
case class Point(x: Int, y: Int)
def f1(w: Point, l: List[String]) = { /* do something /* }
我通常会这样使用它:
val w = Point(1,1)
val lst = List("Hello", "world")
f1(w, lst) // non empty list
我需要多次调用带有空列表的函数作为第二个参数:
f1(w, List()) // empty list
f1(w, Nil) // empty list
最后两行之间是否有任何性能差异?
我认为使用List()
会调用List.apply()
方法。 Scala编译器是否将其优化为Nil
?
注意:Nil
与List()
之间是否存在性能差异? Scala编译器在这里做了什么优化吗?
答案 0 :(得分:7)
有这样的课程
import collections.immutable.List
class Test {
val l = List() // or Nil
}
编译它们,然后用javap -v
List()
给出:
5: getstatic #26 // Field scala/collection/immutable/Nil$.MODULE$:Lscala/collection/immutable/Nil$;
8: putfield #14 // Field l:Lscala/collection/immutable/List;
Nil
给出了:
5: getstatic #24 // Field scala/collection/immutable/Nil$.MODULE$:Lscala/collection/immutable/Nil$;
8: putfield #13 // Field l:Lscala/collection/immutable/Nil$;
因此,两者的字节码(和性能)是相同的。可能还有其他理由选择其中一个,如Govind在评论中链接的问题所述。
深入潜入兔子洞:
查看源List()是List.apply()的糖,它是这样实现的:
def apply[A](xs: A*) = xs.toList
toList
来自TraversableOnce
,并调用to[List]
,其隐含地带有CanBuildFrom[Nothing, A, List[A]]
,在这种情况下为List.canBuildFrom
,后者又来自ReusableCBF
{1}},然后使用.apply()
,++= the empty array
,然后build()
如何将此消除/转换为getstatic
List()
对我来说是非常清楚的。 (或者我在途中错过了一些聪明的东西)。