我有一个返回一个简单函数数组的方法,该数组只打印它们的订单号:
def buggyClosureFunction(amount: Int) = {
val functions = new Array[() => Unit](amount);
var i = 0;
while (i < amount) {
functions(i) = {()=>print(i + " ")}
i += 1;
}
functions
}
val wow = buggyClosureFunction(4);
wow.foreach(_());这将打印4 4 4。(所有函数都打印它们引用的i值。我似乎不能改变我的方法,这样返回的函数就会打印出12,2,3,4。
我的一次尝试是:
def goodClosureFunction(amount: Int) = {
val functions: = new Array[() => Unit](amount);
var i = 0;
val helper = (num: Int) => {
print(num);
}
while (i < amount) {
functions(i) = {()=>helper(i)()}
i += 1;
}
functions
}但这个仍然印着44-4。
发布于 2016-04-30 21:57:08
当您关闭var i = 0时,Scala编译器将将i从scala.Int转换为scala.runtime.IntRef,并将其提升到编译器生成的类中。这意味着生成的类保存对上述类型的引用。当函数被执行时,该值实际上指向最后一个值,而不是保存每个迭代的值。
为了避免这种情况,在闭包中创建i的本地副本:
while (i < amount) {
functions(i) = {
val j = i
() => print(j + " ")
}
i += 1;
}正如@Łukasz所指出的,如果您想使用函数式方法并避免闭包麻烦和可变状态:
def nonBuggyNoClosure(n: Int) = (0 until n) map (i => () => print(i + " "))更详细地介绍How are closures implemented in scala?中Scala闭包的实现细节
https://stackoverflow.com/questions/36960616
复制相似问题