如何在scala中实现闭包? [英] How are closures implemented in scala?

查看:111
本文介绍了如何在scala中实现闭包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

创建函数后,函数范围之外的变量如何拉入函数?我试着反编译,但我有麻烦理解它。它看起来像使用putfield。 putfield是否指向对象引用?

How are the variables outside of the scope of the function pulled into the function when it's created? I tried decompiling, but I had trouble understanding it. It looked like it uses putfield. Does putfield make a pointer to an object reference?

推荐答案

答案是它取决于。这可能会有一些重大的变化与scala 2.11版本。希望2.11能够内联简单的闭包。

The answer is "it depends". There will probably be some major changes to this with the scala 2.11 release. Hopefully 2.11 will be able to inline simple closures.

但无论如何,让我们试着给出一个答案的当前scala版本(下面的javap是从scala 2.10.2)。下面是一个非常简单的闭包,它使用val和var,以及生成的闭包类的javap输出。如您所见,如果您捕获了var或捕获了val,则会有主要区别

But anyway, let's try to give an answer for the current scala version (javap below is from scala 2.10.2). Below is a very simple closure that uses a val and a var, and the javap output of the generated closure class. As you can see there is a major difference if you capture a var or if you capture a val.

如果你捕获一个val,它只是作为副本传递给closure类(你可以这样做,因为它是一个val)。

If you capture a val it just gets passed to the closure class as a copy (you can do this since it is a val).

如果捕获一个var,var本身的声明必须在调用站点位置更改。而不是位于栈上的局部int,var变成 scala.runtime.IntRef 。这基本上只是一个盒子整数,但是有一个可变的int字段。

If you capture a var, the declaration of the var itself has to be changed at the call site location. Instead of a local int that sits on the stack, the var gets turned into an object of type scala.runtime.IntRef. This is basically just a boxed integer, but with a mutable int field.

(这有点类似于使用一个最终数组大小为1的java方法更新匿名内部类中的字段)

(This is somewhat similar to the java approach of using a final array of size 1 when you want to update a field from inside an anonymous inner class)

这对性能有一些影响。当在闭包中使用var时,必须生成闭包对象以及包含var的xxxRef对象。一个平均值是,如果你有一块代码像这样:

This has some impact on performance. When you use a var in a closure, you have to generate the closure object and also the xxxRef object to contain the var. One mean thing is that if you have a block of code like this:

var counter = 0
// some large loop that uses the counter

添加一个闭包,捕获其他地方的计数器,将显着降低。

And add a closure that captures counter somewhere else, the performance of your loop will be lowered significantly.

所以底线是:捕获vals通常不是一件大事,但是要非常小心捕获vars

So the bottom line is: capturing vals is usually not a big deal, but be very careful with capturing vars.

object ClosureTest extends App {
  def test() {
    val i = 3
    var j = 0
    val closure:() => Unit = () => {
      j = i
    }
    closure()
  }
  test()
}

这里是生成的闭包类的javap代码:

And here is the javap code of the generated closure class:

public final class ClosureTest$$anonfun$1 extends scala.runtime.AbstractFunction0$mcV$sp implements scala.Serializable {
  public static final long serialVersionUID;

  public final void apply();
Code:
  0: aload_0       
  1: invokevirtual #24                 // Method apply$mcV$sp:()V
  4: return        

  public void apply$mcV$sp();
Code:
  0: aload_0       
  1: getfield      #28                 // Field j$1:Lscala/runtime/IntRef;
  4: aload_0       
  5: getfield      #30                 // Field i$1:I
  8: putfield      #35                 // Field scala/runtime/IntRef.elem:I
  11: return        

  public final java.lang.Object apply();
Code:
  0: aload_0       
  1: invokevirtual #38                 // Method apply:()V
  4: getstatic     #44                 // Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
  7: areturn       

  public ClosureTest$$anonfun$1(int, scala.runtime.IntRef);
Code:
  0: aload_0       
  1: iload_1       
  2: putfield      #30                 // Field i$1:I
  5: aload_0       
  6: aload_2       
  7: putfield      #28                 // Field j$1:Lscala/runtime/IntRef;
  10: aload_0       
  11: invokespecial #48                 // Method scala/runtime/AbstractFunction0$mcV$sp."<init>":()V
  14: return        
}

这篇关于如何在scala中实现闭包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆