让我们看几个例子。
scala> import scala.util.Random
import scala.util.Random
scala> :paste
// Entering paste mode (ctrl-D to finish)
Seq(1, 2, 3).map {
val rand = new Random().nextInt
_ + rand
}
// Exiting paste mode, now interpreting.
res0: Seq[Int] = List(-921709014, -921709013, -921709012)
scala> :paste
// Entering paste mode (ctrl-D to finish)
Seq(1, 2, 3).map {
_ + new Random().nextInt
}
// Exiting paste mode, now interpreting.
res1: Seq[Int] = List(-884268781, 516035717, -2054776549)
scala> :paste
// Entering paste mode (ctrl-D to finish)
Seq(1, 2, 3).map { i =>
val rand = new Random().nextInt
i + rand
}
// Exiting paste mode, now interpreting.
res2: Seq[Int] = List(-1258337635, 1817183115, -1994392)
在这里,res0
的值被添加到同一个随机数中,这表明相同的随机数生成了三次(极不可能),或者只生成了一个随机数。 res1
看起来符合预期,但它告诉我们直接函数调用,而无需按预期分配给val
生成的随机数。最后,res2
看起来也正确,唯一的区别是使用了变量而不是使用_
。
我很难理解为什么res0
和res2
的行为不同。特别是,为什么res0
没有像人们期望的那样表现。
第一个:
Seq(1, 2, 3).map {
val rand = new Random().nextInt
_ + rand
}
相当于:
// nextInt is outside the body of the function given to map
Seq(1, 2, 3).map({
val rand = new Random().nextInt // nextInt evaluated once here (before map)
i => i + rand // only this function given to map
})
第二种:
Seq(1, 2, 3).map {
_ + new Random().nextInt
}
相当于:
// nextInt is inside the body given to map
Seq(1, 2, 3).map {
i => i + new Random().nextInt
}
给定您的代码:
Seq(1, 2, 3).map {
val rand = new Random().nextInt
_ + rand
}
这可以重写为:
Seq(1, 2, 3).map({
val rand = new Random().nextInt
x => x + rand
})
在这里你可以看到,rand
值不是在实际的函数定义x => x + rand
中计算的。它从定义函数的上下文中关闭。所以基本上它是一个结束。因此,每当计算函数x => x + rand
时,都会重用先前计算的rand
值。
有关更多详细信息,请查看 Programming in Scala 一书中的函数和闭包(8.7 闭包)一章。