我有一些功能:
def f(x: Int) = x * x
然后我称之为:
var y = 0
f { y += 1; y }
为上面的代码生成的字节代码如下:
0: iconst_0
1: istore_1
2: aload_0
3: iload_1
4: iconst_1
5: iadd
6: istore_1
7: iload_1
8: invokevirtual #18 // Method f:(I)I
11: pop
12: return
如果我更改函数 def f(x:Int)来表示按姓名调用:
def f(x: => Int) = x * x
生成的代码相同部分的字节码如下:
0: new #24 // class scala/runtime/IntRef
3: dup
4: iconst_0
5: invokespecial #28 // Method scala/runtime/IntRef."<init>":(I)V
8: astore_1
9: aload_0
....
我的问题是:
对于Call-by-Name,我们是否会对引用进行操作或依赖于编译中的语义分析阶段?
答案 0 :(得分:2)
按名称形式参数的实际参数总是被打包成一个所谓的“thunk”(术语在20世纪60年代一直回到Algol),这使得有可能存在零,一个或多个(对包含实际参数的表达式的任何数量的评估。如果该表达式中存在副作用,那么关于多次评估的这一点很重要。
该“引用”的具体用法与这样一个事实有关,即在被调用函数中执行的代码将对<的一个局部变量(字面意思,特别是var
)产生副作用。 em>调用方法。这就是IntRef
涉及的原因。在这种情况下,将始终使用某种或那种“ref”(取决于在实际参数表达式中引用的var
的类型)。如果不涉及var
,则只将值复制到thunk。