我对在Scala中使用call-by-name参数感到有些困惑。请帮我理解这里发生了什么。请考虑以下使用call-by-name参数的示例:
def param = {println("Param evaluates"); 40}
def lazyEval(x: => Int) = {
println("lazy");
x
}
val s = lazyEval(param + 2)
// s = 42
我有几个问题彼此相关:
lazyEval
方法需要=> Int
类型的参数,那么为什么param + 2
操作合法?为什么我们可以在调用=> Int
方法时将整数2添加到类型为<function0>
的对象(我的理解是lazyEval
)?正如IDE提示我的那样,lazyEval
函数需要Int
类型的参数而不是=> Int
(这到底是什么?)。
为什么在将回调类型从=> Int
更改为() => Int
代码后无法编译?这两种类型有什么不同吗?我虽然短版本('=&gt; Int')只是一个语法糖。
在玩了一些代码后,我终于可以更改代码,以便用() => Int
进行编译。这种方式对我来说更直观。
def param = {println("Param evaluates"); 40}
def lazyEval(x: () => Int) = { // changed type to '() => Int'
println("lazy");
x() // explicitly calling function using parentheses '()'
}
val s = lazyEval(param _) // adding underscore after method name and removing `+2`
此版本与第一版(回调=> Int
类型)之间有何区别?为什么在这个版本中我们不能添加值为2
的整数和param
函数(我的意思是lazyEval(param _ + 2)
)?什么意思是方法名称后面的下划线? (我猜它曾用于传递方法本身,而不是返回值)
感谢您的帮助
答案 0 :(得分:3)
那么为什么param + 2操作合法?为什么我们可以使用type =&gt;向对象添加整数2 INT
我们可以将2
添加到param
,因为它评估为Int
,您正在Int
添加Int
。 param
不是函数=> Int
,它是一种方法,因此param + 2
是 => Int
。即。表达式,其值为Int
。
为什么在更改回调类型后从=&gt; Int to()=&gt; Intcode没有编译?这两种类型有什么不同吗?我虽然简短的版本(&#39; =&gt; Int&#39;)只是一个语法糖。
=> Int
和() => Int
并不意味着同样的事情。一个是评估为Int
的任何内容,另一个是Unit
到Int
的函数。 2
不是() => Int
,而是() => 2
。或者您也可以说2
是=> Int
。
为什么在这个版本中我们不能添加值为2的整数和param函数(我的意思是thislazyEval(param _ + 2))?什么意思是方法名称后面的下划线? (我猜它曾用于传递方法本身,而不是返回值)
param
是一种方法,而不是一种功能。在这种情况下,下划线将param
提升为一个函数。因此param _
是一个函数() => Int
。这正是我们无法向其添加2
的原因,因为您无法将2
添加到某个功能中。基本上你认为(1)不应该工作的确切原因。
总结:
def lazyEval(x: => Int)
是一个参数x
的方法,可以任何评估为Int
的内容。这可以是返回Int
的任何方法,具体值Int
,或解析为Int
的某些代码块等。
lazyEval(x: () => Int)
是一个参数x
的方法, 只能是一个返回Int
的无参数函数。这可能意味着方法param
被提升到一个函数,或者像() => 2
那样奇怪的东西。但它必须是一个功能。因此,简单地传递像2
这样的值是行不通的。
答案 1 :(得分:2)
正如@mz指出的那样,value: => T
可以被认为是语法,用于创建包装给定表达式的方法 :
object Magician {
def magic(param: => Int) = param
}
object App {
val result: Int = Magician.magic(3 + 3)
}
将(粗略地)翻译为:
object App {
private[this] def magic$param$1: Int = 3 + 3
val result: Int = Magician.magic(magic$param$1 _)
}
call-by-name参数的行为类似于无参数方法定义 - 引用任一导致被调用的方法:
def paramlessMethod = 3 + 3
def callByName(param: => Int) = param + paramlessMethod
def test() = callByName(5 + 5) // 16, always
在这两种情况下,你都可以解除&#34; Function0
的方法(或者#34;推迟评估方法&#34;如果你喜欢这样思考的话)使用魔法_
:
def paramlessMethod = 3 + 3
val functionWrapper: Function0[Int] = paramlessMethod _
functionWrapper() // 6
def callByName(param: => Int) = param _
val functionFromParam: Function0[Int] = callByName(3 + 3)
functionFromParam() // 6
答案 2 :(得分:1)
此处解释def i: Int
的类型:
http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#method-types
此处解释了名称参数i: => Int
的类型:
这样的参数的类型是无参数方法type =&gt; 吨。
换句话说,它与方法类型def i: Int
相同。