功能后下划线?

时间:2016-09-19 12:58:14

标签: scala

鉴于

scala> def method(x: Int) = x
method: (x: Int)Int

scala> val func = (x: Int) => x
func: Int => Int = <function1>

请考虑以下代码:

scala> method _
res0: Int => Int = <function1>

scala> func(_)
res1: Int => Int = <function1>

scala> func _
res2: () => Int => Int = <function0>

我可以理解res0是eta扩展而res1等同于lambda函数(x) => func(x)。但我无法弄清楚res2的输出。有人可以帮我解释一下吗?

4 个答案:

答案 0 :(得分:6)

这实际上有点棘手。首先,让我们看看REPL之外会发生什么:

func是一个局部变量时

没有工作:

object Main extends App {
  def foo() = {
    val f = (_: Int) + 1
    f _
  }

  println(foo())
}

[error] /tmp/rendereraEZGWf9f1Q/src/main/scala/test.scala:8: _ must follow method; cannot follow Int => Int
[error]     f _
[error]     ^

但如果你把它放在def foo之外,它会编译:

object Main extends App {
  val f = (_: Int) + 1
  val f1 = f _

  println(f1)
}

因为f既是Main字段,又是没有参数的方法,它返回此字段的值。

最后一块是REPL将每一行包装成一个对象(因为Scala不允许代码出现在特征/类/对象之外),所以

scala> val func = (x: Int) => x
func: Int => Int = <function1>    

真的像

object Line1 {
  val func = (x: Int) => x
}
import Line1._
// print result

所以下一行的func引用Line1.func这是一种方法,因此可以进行eta扩展。

答案 1 :(得分:3)

您已经使用eta Expansion将res2转换为一个接受0参数的函数,并返回一个带有单个参数的函数。

res2: () => Int => Int = <function0>

所以你现在可以这样做:

val zero = func _
val f: Int => Int = zero()

答案 2 :(得分:2)

val func1 = func _

这将返回一个不带参数的函数0并返回func函数。

你可以使用它:

func1()(2) // outputs 2

您可以无限制地继续进行此类扩展:

val func2 = func1 _

func2()()(2) // outputs 2

答案 3 :(得分:2)

要回答有关res2的问题,我们会使用附加的下划线_语法来部分应用函数。

所以

scala> func _

表示您已部分应用了<function1>。 这会产生一个新的curry形式,其第一个函数采用零参数(因此<function0>

() =>

返回原始<function1>,其中包含1个参数。

Int => Int = <function1>

完整的结果是功能链。

res2: () => Int => Int = <function0>

可能对您有用的规则是函数与右侧相关联,因此以下内容是等效的。

() => Int => Int    
() => (Int => Int)

This other post可能对您有用。