在这个comment中,@ Ben建议按名称调用等价于按值调用,其中值为零参数函数。如果我理解正确,
def callByName(x: => Int) = {
// some code
}
callByName(something())
相当于
def callByValue(x: () => Int) = {
// same code as above, but all occurrences of x replaced with x()
}
callByValue(()=>something())
(编辑:我修正了@MichaelZajac指出的签名错误,@ LukaJacobowitz:最初,它说callByValue(x: Int)
。)
换句话说,整个“按名称调用”概念只是语法糖:它所做的一切都可以通过“按值调用”来实现(通过一些额外的击键)。如果是真的,它可以很容易地理解名字的呼叫;事实上,我在python中使用过这种技术(python具有一流的功能)。
然而,在comments中,讨论变得更加混乱,我感觉它不是那么简单。
那么“名字叫”是否更具实质性?或者只是编译器自动创建零参数函数?
答案 0 :(得分:1)
我假设你的callByValue
函数意味着要() => Int
而不仅仅是Int
,否则它就没有多大意义。
这几乎就是你的想法。编译器生成Function0
实例。当您使用Javap
反编译Scala代码时,您可以很好地看到这一点。
另外需要注意的是,每次在函数中使用by-name参数时,都会重新评估生成的Function0
,所以如果你只想在计算机上执行某项操作就计算它像这样:
def callByName(x: => Int) = {
val a = x
// do something with a here
}
Here是关于整个概念的更多信息。 此外,您还可以看到Scala如何在this question中非常整齐地编译名称参数:
def getX[T <: X](constr: ⇒ T): Unit = {
constr
}
用Java反编译相当于:
public <T extends X> void getX(Function0<T> constr) {
constr.apply();
}
答案 1 :(得分:1)
是的,但你的例子并不完全正确。您的问题中所写的callByValue
签名将在x
被调用之前评估callByValue
。
以下内容大致相当于按名称调用:
def callByValue(x: () => Int) = {
// same code as above, but all occurrences of x replaced with x()
}
区别很重要,因为您的callByValue
版本只接受Int
s,而不是返回Int
s的函数。如果您遵循将x
替换为x()
的过程,也无法编译。
但是,=> A
的按名称调用参数大致相当于() => A
,除了前者更方便使用。我说粗略因为是不同的类型,他们的应用程序略有不同。您可以指定() => A
作为某种类型,但不是=> A
。当然,使用x: () => A
时,您必须手动拨打x()
而不是x
。