2

说,首先,我有这个功能:

def number5()={
      println("number 5 starting")
      println("number 5 exiting")
      5
}

接着:

def giveMeCallByNameParameter(f: =>Int)={
      println("starting")
      f
      println("exiting")
}

当我调用它时:

giveMeCallByNameParameter(number5)

我得到这个结果:

starting
number 5 starting
number 5 exiting
exiting

如果我也有这个功能:

def giveMeAnotherFunction(f: ()=>Int)={
      println("starting")
      f()
      println("exiting")
}

我称之为:

giveMeAnotherFunction(number5)

我得到相同的结果:

starting
number 5 starting
number 5 exiting
exiting

那么,它们有什么不同吗?除了有或没有括号的区别吗?

如果他们没有不同?那么为什么我们有这个术语的名称呢?

4

4 回答 4

3

按名称参数可以是任何有效的表达式。函数也是有效的表达式,但只是一种表达式。

按名称参数和按值参数之间的最大区别在于,按值参数是最常见的函数参数,在传递给函数之前会先进行评估。按名称参数的评估至少要延迟到被传递到函数之后。函数本身可能会或可能不会评估参数,它没有义务这样做。

恰巧函数具有这种相同的属性,但同样,正如我之前所说,函数只是一种表达式,而名称参数可以采用任何类型的有效表达式。

按名称参数的一个很好的用例是构建自定义断言函数:

def byNameAssert(predicate: => Boolean) =
  if (assertionsEnabled && !predicate)
    throw new AssertionError

这样,您可以通过控制值来关闭对断言条件的评估assertionsEnabled

如果没有启用断言,你甚至可以有一个表达式,它通常会抛出,而不是产生异常:

byNameAssert(x / 0 == 0)

另请注意,表达式 ,x / 0 == 0不是函数!By-name 参数可以采用任何类型的表达式,但会将其评估推迟到至少在调用函数之后。

希望这可以帮助!

于 2014-09-24T14:41:35.773 回答
2

在此特定示例中,两者看起来相同。但是考虑一下这个用例

giveMeCallByNameParameter(number5 * number5)

你得到这个结果:

起始
编号 5 起始
编号 5 退出
编号 5 起始
编号 5 退出
退出

如果您尝试在 上做同样的事情giveMeAnotherFunction,它将无法编译

scala> giveMeAnotherFunction(number5() * number5())
:10: 错误:类型不匹配;
找到:
需要 Int:() => Int
giveMeAnotherFunction(number5() * number5())

您必须发送一个函数而不仅仅是任何表达式

giveMeAnotherFunction(() => number5 * number5)
于 2014-09-24T15:00:58.557 回答
1

据我所知,至少在你的例子中没有区别。

于 2014-09-24T14:33:47.913 回答
0

它们是有区别的。

  • 名称调用仅在您使用它时进行评估,它也需要一个
  • 另一方面,函数是映射而不是

因此,因此您将方法更改number5为函数,您不能使用按名称调用,但可以在函数中使用

def number5()={
  println("number 5 starting")
  println("number 5 exiting")
  5
}

def func: () => Int = number5 // change method to function

def giveMeCallByNameParameter(f: =>Int)={
  println("starting")
  f
  println("exiting")
}

giveMeCallByNameParameter(func) //compilation error

def giveMeAnotherFunction(f: ()=>Int)={
  println("starting")
  f()
  println("exiting")
}

giveMeAnotherFunction(func) // this is fine

此外,您可以在需要functiongiveMeAnotherFunction中使用方法的原因是因为ETA-expansion。有很多使用它的示例,例如 map、foldLeft 等。

于 2014-09-25T04:24:01.347 回答