为什么按名称调用的参数期望 Int 类型的参数而不是 () => Int

Why call-by-name parameter expect parameter of type Int instead of () => Int

我对在 Scala 中使用按名称调用参数有点困惑。请帮助我了解这里发生了什么。考虑以下使用按名称调用参数的示例:

  def param = {println("Param evaluates"); 40}
  def lazyEval(x: => Int) = {
    println("lazy"); 
    x 
  }
  val s = lazyEval(param + 2)
  // s = 42

关于这个我有几个相互关联的问题:

  1. lazyEval方法需要=> Int类型的参数,那么为什么param + 2操作是合法的呢?为什么我们可以在调用 lazyEval 方法时将整数 2 添加到类型为 => Int 的对象(我的理解是 <function0>)?正如 IDE 提示我的那样,lazyEval 函数需要 Int 类型的参数而不是 => Int (到底是什么?)。

  2. 为什么将回调类型从 => Int 更改为 () => Int 代码无法编译?这两种类型不同吗?我虽然简短的版本 ('=> Int') 只是一个语法糖。

  3. 在尝试了一些代码之后,我终于可以更改代码以便它可以使用 () => 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))?方法名称后的下划线是什么意思? (我猜它曾经传递方法本身,而不是 return 值)

感谢帮助

so why param + 2 operation is legal? Why we can add integer 2 to object with type => Int

我们可以将 2 添加到 param,因为它的计算结果是 Int,您正在添加 IntIntparam 不是一个函数 => Int,它是一个方法,所以 param + 2 => Int。 IE。计算结果为 Int.

的表达式

Why after changing callback type from => Int to () => Intcode doesn't compile? Is this 2 types are different? I though the short version ('=> Int') is just a syntactical sugar.

=> Int() => Int 不是一个意思。一个是计算结果为 Int 的任何值,另一个是从 UnitInt 的函数。 2 不是 () => Int,但 () => 2 是。或者你也可以说 2=> Int.

Why in this version we can't make addition of integer with value 2 and the param function (I mean thislazyEval(param _ + 2))? And what mean underscore after method name? (I guess it used to pass method itself, not it return value)

param 是方法,不是函数。本例中的下划线将 param 提升为一个函数。所以 param _ 是一个函数 () => Int。这正是我们不能将 2 添加到它的原因,因为您不能将 2 添加到函数。基本上就是您认为 (1) 不可行的确切原因。


总结:

def lazyEval(x: => Int) 是一个带有参数 x 的方法,它可以是 任何计算结果为 Int 的东西。这可以是 returns Int 的任何方法,Int 的具体值,或者解析为 Int 的某个代码块,等等

lazyEval(x: () => Int)是一个有参数x的方法,它只能是returnsInt的无参数函数。这可能意味着方法 param 被提升为一个函数,或者像 () => 2 这样奇怪的东西。但它必须是一个函数。所以简单地传递一个像 2 这样的值是行不通的。

正如@m-z 指出的那样,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: Int = 3 + 3
    val result: Int = Magician.magic(magic$param _)
}

按名称调用参数的 行为 类似于无参数方法定义 - 引用任一方法都会导致调用该方法:

def paramlessMethod = 3 + 3
def callByName(param: => Int) = param + paramlessMethod
def test() = callByName(5 + 5) //  16, always

在这两种情况下,您都可以 "lift" 通过使用魔术 _ Function0(或者 "defer the evaluation of the method",如果您更愿意这样想的话)的方法]:

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

这里解释def i: Int的类型:

http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#method-types

别名参数的类型i: => Int解释如下:

http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#by-name-parameters

The type of such a parameter is then the parameterless method type => T.

也就是说和方法类型一样def i: Int.