1

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

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

关于这个,我有几个彼此相关的问题:

  1. lazyEval方法需要 type 的参数=> Int,那么为什么param + 2操作是合法的?为什么我们可以在调用方法时将整数 2 添加到具有类型的对象=> Int(我的理解是在底层) ?正如 IDE 提示我的那样,该函数需要类型参数而不是(到底是什么?)。<function0>lazyEvallazyEvalInt=> 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这个版本和第一个版本(带有回调类型)有什么区别?为什么在这个版本中我们不能将整数与值2param函数相加(我的意思是 this lazyEval(param _ + 2))?方法名称后的下划线是什么意思?(我猜它曾经传递方法本身,而不是返回值)

感谢帮助

4

3 回答 3

3

那么为什么 param + 2 操作是合法的呢?为什么我们可以将整数 2 添加到 type => Int 的对象

我们可以添加2到,param因为它评估为Int,您正在Int添加Intparam不是函数=> Int,它是方法,所以param + 2 => Int。IE。计算结果为 的表达式Int

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

=> Int并不() => Int意味着同样的事情。一个是计算结果为 的任何东西,Int另一个是来自Unitto的函数Int2不是() => Int,而是() => 2。或者你也可以说2is => 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行不通的。

于 2015-03-22T02:40:18.883 回答
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 _)
}

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

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

在这两种情况下,您都可以使用以下魔法将方法“提升”到 a Function0(或“推迟对方法的评估”,如果您更愿意这样想的话)_

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
于 2015-03-22T04:30:20.970 回答
1

的类型在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

这样一个参数的类型就是无参数方法类型 => T。

换句话说,它与方法类型相同def i: Int

于 2015-03-22T08:12:50.823 回答