按值调用,将值解释为零参数函数与按名称调用

时间:2016-12-30 20:41:30

标签: scala

在这个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中,讨论变得更加混乱,我感觉它不是那么简单。

那么“名字叫”是否更具实质性?或者只是编译器自动创建零参数函数?

2 个答案:

答案 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