在Scala中,是一个函数,它通过name参数调用,不同于另一个函数作为参数的函数?

时间:2014-09-24 14:31:02

标签: scala functional-programming terminology higher-order-functions callbyname

首先,我有这个功能:

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 个答案:

答案 0 :(得分:3)

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

按名称参数和按值参数之间的最大区别在于,在传递给函数之前,评估了按值参数(最常见的函数参数)。至少在传递给函数之后,名称参数的评估被延迟。函数本身可能会或可能不会评估参数,它没有义务。

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

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

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

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

如果未启用断言,您甚至可以使用一个通常会抛出的表达式,而不会产生异常:

byNameAssert(x / 0 == 0)

还要注意表达式x / 0 == 0不是函数!按名称参数可以采用任何类型的表达式,但至少会在调用函数之后推迟评估。

希望这有帮助!

答案 1 :(得分:2)

在这个特定的例子中,两者看起来都一样。但请考虑这个用例

giveMeCallByNameParameter(number5 * number5)

你得到这个结果:

  

开始
  5号出发   5号退出
  5号出发   5号退出
  退出

如果您尝试在giveMeAnotherFunction上执行相同操作,则无法编译

  

阶> giveMeAnotherFunction(number5()* number5())
  :10:错误:类型不匹配;
   发现:Int
  必需:()=>诠释
               giveMeAnotherFunction(number5()* number5())

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

giveMeAnotherFunction(() => number5 * number5)

答案 2 :(得分:1)

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

答案 3 :(得分:0)

有区别。

  • 按名称调用仅在您使用它时进行评估,也期望a 的
  • 另一方面,功能是不是
  • 的映射

因此,您将方法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

此外,您可以在 giveMeAnotherFunction 中使用方法的原因是功能,原因是 ETA-expansion 。有很多使用它的例子,如map,foldLeft等。