Scala 捕获变量的嵌套函数是否分配
scala中的嵌套函数可以捕获父函数中的变量 e、 g def外部={ 变量a=0 def内部={ a=42 } 内部的 A. } 在C中,这是通过将所有捕获的变量存储在一个结构上,并在byref中传递该结构来实现的。这避免了嵌套函数的分配,除非将其转换为函数对象。在夏普实验室见 但是,在scala中,您不能通过ref传递变量,因此唯一可行的方法是将所有捕获的变量存储在一个对象上,然后将该对象传入 这是否意味着,如果嵌套函数捕获scala中的任何变量,它的每次调用都将进行分配?变量a本身仍然位于外部方法的堆栈框架中,而它引用的对象在堆上进行分配,因为即使假定a代表基元类型,所有Java对象也是如此 通过在您的代码上运行javap-v,我们可以看到a实际上是scala.runtime.IntRef类型的最终变量,它包含一个可以更新的整数字段。嵌套的内部方法被转换为一个静态方法,该方法接受一个IntRef类型的参数,并将其elem字段设置为42。这有点类似于C方法,但是为每个变量创建一个对象,而不是一个结构来保存所有变量Scala 捕获变量的嵌套函数是否分配,scala,closures,nested-function,Scala,Closures,Nested Function,scala中的嵌套函数可以捕获父函数中的变量 e、 g def外部={ 变量a=0 def内部={ a=42 } 内部的 A. } 在C中,这是通过将所有捕获的变量存储在一个结构上,并在byref中传递该结构来实现的。这避免了嵌套函数的分配,除非将其转换为函数对象。在夏普实验室见 但是,在scala中,您不能通过ref传递变量,因此唯一可行的方法是将所有捕获的变量存储在一个对象上,然后将该对象传入 这是否意味着,如果嵌套函数捕获scala中的任何变量,它的每次调用都将进行分配?变量a本身仍然位于
public int outer();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=2, args_size=1
0: iconst_0
1: invokestatic #16 // Method scala/runtime/IntRef.create:
(I)Lscala/runtime/IntRef;
4: astore_1
5: aload_1
6: invokestatic #20 // Method inner$1:(Lscala/runtime/IntRef;)V
9: aload_1
10: getfield #24 // Field scala/runtime/IntRef.elem:I
13: ireturn
编辑:这次让我们用字符串试试:
class ClosureTest {
def outer = {
var a = ""
def inner() = {
a = "42"
}
inner()
a
}
}
javap的输出:
这一次,由于String不是一个原语,所以使用了ObjectRef类,它有一个表示包装值的类型参数,但基本上还是一样的。尽管JVM不允许像C一样使用ref参数,但对象仍然是通过引用传递的,因此a保留的对象/原语的值仍然可以修改
这是我能找到的唯一文档的一个例子。还有很多其他类,比如BooleanRef、FloatRef,还有它们的volatile对应类,比如VolatileDoubleRef、VolatileObjectRef,等等。这些类中的每个类基本上只有一个可变公共字段,编译器在需要捕获变量的实际值时使用该字段。变量a本身仍在外部方法的堆栈框架中,而它引用的对象在堆上分配,因为所有Java对象都是,甚至当一个被认为代表一个基本类型时
通过在您的代码上运行javap-v,我们可以看到a实际上是scala.runtime.IntRef类型的最终变量,它包含一个可以更新的整数字段。嵌套的内部方法被转换为一个静态方法,该方法接受一个IntRef类型的参数,并将其elem字段设置为42。这有点类似于C方法,但是为每个变量创建一个对象,而不是一个结构来保存所有变量
public int outer();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=2, args_size=1
0: iconst_0
1: invokestatic #16 // Method scala/runtime/IntRef.create:
(I)Lscala/runtime/IntRef;
4: astore_1
5: aload_1
6: invokestatic #20 // Method inner$1:(Lscala/runtime/IntRef;)V
9: aload_1
10: getfield #24 // Field scala/runtime/IntRef.elem:I
13: ireturn
编辑:这次让我们用字符串试试:
class ClosureTest {
def outer = {
var a = ""
def inner() = {
a = "42"
}
inner()
a
}
}
javap的输出:
这一次,由于String不是一个原语,所以使用了ObjectRef类,它有一个表示包装值的类型参数,但基本上还是一样的。尽管JVM不允许像C一样使用ref参数,但对象仍然是通过引用传递的,因此a保留的对象/原语的值仍然可以修改
这是我能找到的唯一文档的一个例子。还有很多其他类,比如BooleanRef、FloatRef,还有它们的volatile对应类,比如VolatileDoubleRef、VolatileObjectRef,每个类基本上只有一个可变公共字段,编译器在需要捕获变量的实际值时使用该字段。在创建嵌套函数时捕获变量,而不是在调用嵌套函数时。在创建嵌套函数时捕获变量,而不是在调用嵌套函数时捕获变量。