不同地定义Scala函数

时间:2012-03-27 15:45:39

标签: function scala

  

可能重复:
  Difference between method and function in Scala
  Two ways of defining functions in Scala. What is the difference?

定义一个函数有两种方法。

scala> def a : (Int, Int) => Int = {(s:Int, t:Int) => s + t}
a: (Int, Int) => Int

scala> a
res15: (Int, Int) => Int = <function2>

scala> def b(s:Int, t:Int) : Int = s+t
b: (s: Int, t: Int)Int

scala> b
<console>:9: error: missing arguments for method b in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
              b
              ^

scala> b(3,4)
res17: Int = 7

scala> a(3,4)
res18: Int = 7

我如何定义函数a和b有什么不同吗?为什么我的b参数错误?

2 个答案:

答案 0 :(得分:6)

b不是函数,而是方法。但是,您可以通过添加编译器提及的b_转换为函数。 val f = b _。但是,如果要将对象的方法传递给将函数作为参数的方法/函数,则应该只执行此操作。如果你只是想以正常的方式定义一个函数。

但要回答你的问题,还有另外一种方法:

val f = new Function2[Int,Int,Int] {
  def apply(x: Int, y: Int) = x + y
}

答案 1 :(得分:2)

面向对象的语言(例如java)通常具有类和类具有方法,而函数不是“一等公民”,这意味着您不能将函数直接分配给变量或将一些函数放在列表中或将它们作为参数发送给其他函数。 如果要在java中发送函数,则必须使用方法创建一个类并发送该类。 例如,如果你想要一个计算其输入的double的函数,你必须把它放在一个类中,如下所示:

class Doubler 
{
  public int apply(int a)
  {
    return a * 2;
  }
}

在函数式编程语言中,如Haskell,函数是“一流的”,你可以将它们存储在变量中并发送它们。

doubleIt :: Integer -> Integer
doubleIt x =  2 * x

作为功能和面向对象的完美结合,scala具有方法和功能。

// a function like in haskell
val doubleIt = (x:Int) => x * 2 

// a method in an object like in java
object Doubler {
    def apply(x:Int) = x * 2
}

在scala def中始终定义一个方法。请注意,REPL使用main将您在对象中编写的所有内容包装起来(为了能够动态编译和执行它),但编写一个未包含在类/对象/中的def something程序中的特征无法编译。

Scala还提供了一些额外的优势,以减少对象和一流功能之间的脱节。

首先,scala中Doubler对象定义中的“apply”方法有点神奇。 根据上面的定义,您可以编写Doubler(2),scala的编译器会将其转换为Doubler.apply(2),并愉快地返回4。 因此,您可以将对象用作函数。

但是,你也可以(通过在方法调用后放一个_符号)将方法转换为实际函数,并(比如说)将其赋值给val。

scala> val d = Doubler.apply _
d: Int => Int = <function1>

scala> d(2)
res1: Int = 4

另一方面,scala将类似val doubleIt = (x:Int) => x * 2的函数放入第一类“事物”的方式是将它变成背后的类似东西。

object Doubler extends Function[Int, Int] {
  def apply(x: Int) = x*2
} 

val doubleIt = Doubler

所以,是的...一个函数实际上仍然是一个带有方法的类,或多或少像在java中一样。除了scala为你做的并且给你很多语法糖来使用生成的类,因为你将使用实际的函数。

为了让事情变得更有趣,因为函数是一流的,你可以在scala中用它们做的事情之一是将它们用作来自其他函数或方法的返回值。 因此,当您编写def a : (Int, Int) => Int = {(s:Int, t:Int) => s + t}时,您实际上定义了一个名为a的方法,该方法返回一个函数。一开始可能会让人感到困惑(第二次,第三次......)但是第四次左右它可能会开始变得漂亮。至少这是它为我做的。