首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么按名称调用参数期望参数类型为Int而不是() => Int

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

Stack Overflow用户
提问于 2015-03-22 02:20:49
回答 3查看 587关注 0票数 1

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

代码语言:javascript
复制
  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操作是合法的?为什么在调用=> Int方法时,我们可以将整数2添加到带有<function0>类型的对象(我的理解是<function0>)?正如IDE提示我的那样,lazyEval函数需要Int类型的参数,而不是=> Int (到底是什么?)。
  2. 为什么在将回调类型从=> Int更改为() => Int代码后不编译?这两种不同吗?我认为简短的版本('=> Int')只是一个语法糖。
  3. 在玩了一些代码之后,我终于可以修改代码了,这样它就可以用() => Int编译了。这条路对我来说更直观。

代码语言:javascript
复制
  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函数(我指的是这个lazyEval(param _ + 2))来加法整数呢?方法名称后面的下划线是什么意思?(我猜它以前是传递方法本身,而不是返回值)

感谢帮助

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-03-22 02:40:18

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

我们可以将2添加到param中,因为它的计算结果是Int,您要用Int添加Intparam不是一个函数=> Int,它是一个方法,所以param + 2=> Int。即。计算为Int的表达式。

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

=> Int() => Int的意思不一样。一种是计算为Int的任何东西,另一种是从UnitInt的函数。2不是() => Int,但() => 2是。或者你也可以说2=> Int

为什么在这个版本中,我们不能用值2和param函数(我是指thislazyEval(param _+ 2))进行整数的加法?方法名称后面的下划线是什么意思?(我猜它以前是传递方法本身,而不是返回值)

param是一种方法,而不是函数。在这种情况下,下划线将param提升为一个函数。所以param _是一个函数() => Int。这就是为什么我们不能将2添加到其中,因为您不能将2添加到函数中。基本上,你认为(1)不应该起作用的确切原因。

总结如下:

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

lazyEval(x: () => Int)是一个具有参数x的方法,该参数只能是返回Int的无参数函数。这可能意味着param提升到一个函数的方法,或者类似于() => 2之类的奇怪方法。但它一定是一种功能。因此,简单地传递一个像2这样的值就无法工作。

票数 3
EN

Stack Overflow用户

发布于 2015-03-22 04:30:20

正如@m-z所指出的,可以将value: => T视为创建包装给定表达式的方法的语法。

代码语言:javascript
复制
object Magician {
  def magic(param: => Int) = param
}

object App {
  val result: Int = Magician.magic(3 + 3)
}

翻译(大致)为:

代码语言:javascript
复制
object App {
    private[this] def magic$param$1: Int = 3 + 3
    val result: Int = Magician.magic(magic$param$1 _)
}

逐名调用参数的行为类似于无参数的方法定义-引用结果之一是调用方法:

代码语言:javascript
复制
def paramlessMethod = 3 + 3
def callByName(param: => Int) = param + paramlessMethod
def test() = callByName(5 + 5) //  16, always

在这两种情况下,您都可以通过使用神奇的Function0将该方法“提升”到一个_ (或者“推迟方法的评估”,如果您愿意这样想的话)。

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2015-03-22 08:12:50

这里解释了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相同。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29190253

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档