scala closure - 强制绑定值而不是引用

时间:2016-04-30 21:47:20

标签: scala closures

我有一个方法,它返回一个只打印订单号的简单函数数组:

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 4.(所有函数打印它们引用的i的值。 我似乎无法更改我的方法,以便返回的函数将打印1 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
}

但是这个stil打印4 4 4 4。

1 个答案:

答案 0 :(得分:3)

当您关闭var i = 0时,Scala编译器会将iscala.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闭包的实现细节的更多信息