为什么应用于2个函数的部分函数以2种不同的方式执行相同的操作会返回不同的结果?

时间:2012-03-03 04:41:24

标签: scala

我可以定义以下两个函数:

def add(a: Int, b: Int, c: Int) = a + b + c

这导致

add: (a: Int, b: Int, c: Int)Int

val add2 = (a: Int, b: Int, c: Int) => a + b + c

这导致

add2: (Int, Int, Int) => Int = <function3>

这两个函数完全相同,但以不同的方式定义,我不明白的是,如果我继续并按如下方式定义部分应用的函数:

def a = add _

这导致

a: (Int, Int, Int) => Int = <function3> 

如预期的那样,一个函数接受3个参数并返回一个Int,但如果我这样做

def a2 = add2 _

这导致

a2: () => (Int, Int, Int) => Int = <function0>

这似乎是一个不带参数的函数,并返回一个带有3个Int参数并返回Int的函数。为什么会这样?有人可以解释一下发生了什么吗?

感谢

3 个答案:

答案 0 :(得分:9)

这是Scala的一个奇怪的副作用,实际上没有(用户可访问的)字段,而是拥有所有内容的访问者(getter)。观察:

scala> val i = 1
i: Int = 1

scala> i _
res0: () => Int = <function0>

原因是i实际上是底层(隐藏,不可访问)字段的访问者(def i: Int)。由于它只是一种方法,_会将其转换为函数。访问器不带任何参数,这就是为什么你有一个不带参数的函数。

答案 1 :(得分:2)

Scala既有功能又有方法,它们并不完全相同。

def add(a: Int, b: Int, c: Int) = a + b + c

哪个定义了一个方法(不是函数!!)。

val add2 = (a: Int, b: Int, c: Int) => a + b + c

为add2分配了一个函数值(不是方法!!)。

方法不能是最终值,而函数可以:

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

scala> add2
res1: (Int, Int, Int) => Int = <function3>

scala> val a = add
<console>:8: error: missing arguments for method add;
follow this method with `_' if you want to treat it as a partially applied function
       val a = add
               ^

scala> val a2 = add2
a2: (Int, Int, Int) => Int = <function3>

在方法名称后面编写下划线可以将方法显式转换为函数:

scala> add _
res2: (Int, Int, Int) => Int = <function3>

但是如果你在一个值之后写一个下划线,它将转换为一个函数,该函数不带任何参数类型的返回类型:

scala> val s = ""
s: String = ""

scala> val i = 1
i: Int = 1

scala> s _
res3: () => String = <function0>

scala> i _
res4: () => Int = <function0>

因此,如果值本身是一个函数,在它之后写一个下划线将得到一个新的函数,该函数不带有返回类型函数的参数:

scala> add2 _
res5: () => (Int, Int, Int) => Int = <function0>

答案 2 :(得分:1)

效果在Rex Kerr's answer中有明确说明,但您应注意add2是已经代表部分应用功能的值,例如代表。 为了演示,您可以比较add1 _表达式和add2值的类型。

scala> def getManifest[T](x:T)(implicit m:scala.reflect.Manifest[T]) = m
getManifest: [T](x: T)(implicit m: scala.reflect.Manifest[T])scala.reflect.Manifest[T]

scala> getManifest(add1 _) == getManifest(add2)
res14: Boolean = true