2016-12-30 44 views
0

解释为零参数函数VS呼叫在这种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的更深层次,讨论变得更加混乱,我觉得它并不那么简单。

所以有更多的东西实质性“按名字叫”?或者它只是编译器自动创建的零参数函数?

回答

1

我假设你的意思是你的callByValue函数采取() => Int而不仅仅是一个Int否则它不会很有意义。

它几乎正是你的想法。编译器生成一个Function0实例。当您用Javap反编译Scala代码时,您可以很好地看到这一点。

另一件值得注意的事情是,生成的Function0将在每次在函数内部使用by-name参数时重新评估,因此如果您只希望计算一次,则需要执行下面的操作:

def callByName(x: => Int) = { 
    val a = x 
    // do something with a here 
} 

Here是关于整个概念的更多信息。 还可以看到斯卡拉如何this question编译通过名称参数相当整齐:

def getX[T <: X](constr: ⇒ T): Unit = { 
    constr 
} 

用Java反编译等价于:

public <T extends X> void getX(Function0<T> constr) { 
    constr.apply(); 
} 
1

是的,但你的例子是不完全正确。的callByValue签名,写在你的问题,被调用callByValue之前将评估x

以下是大致相当于一个呼叫按姓名:

def callByValue(x:() => Int) = { 
    // same code as above, but all occurrences of x replaced with x() 
} 

的区别是很重要的,因为你的callByValue版本将只接受Int S,不返回Int职能。它如果您是用x()更换x的程序也不会编译。

但是,是的,名称参数=> A大致相当于() => A,只是前者使用起来更方便。我说大致是,因为他们的都是不同的类型,它们的应用有些不同。您可以指定() => A为某种东西,但不包含=> A。当然,使用x:() => A时,您必须手动拨打x()而不是x