Scala占位符行为

时间:2017-04-30 01:36:12

标签: scala foreach

假设l = List(1, 2, 3):

scala> l foreach { println _ }
1
2
3
scala> l foreach { println }
1
2
3

l foreach { println _ } <=> l foreach { println }因为_可以省略。但为什么以下也会产生相同的结果呢?

scala> l foreach { println(_) }
1
2
3

不应该将_限制为println而不是foreach吗? 换句话说:

l foreach { println(_) } <=> l foreach { println(x => x) }

并因此在缺少参数类型时抛出错误? l foreach { println(_.toString) }生成预期的缺失参数类型错误

3 个答案:

答案 0 :(得分:1)

foreach采用函数A => Unit,在本例中为Int => Unit

println满足这个条件,但它是一个方法,而不是一个函数。 Scala可以通过一种称为eta扩展的技术解决这个问题。它创建了一个函数,该函数接受方法的输入并使用这些输入调用方法。在您的情况下,它看起来类似于(x: Int) => println(x)

你写的每一种方式都可以实现这一点。

l foreach { println }

Scala能够推断您希望将println视为一个函数并将其传递给foreach

l foreach { println _ }

通过添加下划线,您明确表示要将方法转换为函数

l foreach {println(_)}

这与上一个类似,对于您调用的任何方法,您可以使用下划线而不是传递参数。通过执行此操作,您可以创建部分应用的函数,而不是调用该方法。然后,您将此功能传递给foreach

l foreach {println(_。toString)}

这有点不同。 _.toString创建了一个函数A => String,但Scala无法确定A的正确类型。另一个问题不是您将值传递给println,因此您调用println并且将结果传递给foreach而不是将其转换为函数。 println会返回Unit,这是传递给foreach

的错误类型

答案 1 :(得分:0)

您忘记了println(x)也可以在Scala中写为println x。如果只有一个参数,则括号是可选的。

答案 2 :(得分:0)

  

_不应该将_绑定到println而不是foreach?换句话说:

l foreach { println(_) } <=> l foreach { println(x => x) }

不,匿名函数中的占位符规则明确排除了这一点:

  

An expression e of syntactic category Expr binds an underscore section u, if the following two conditions hold: (1) e properly contains u, and (2) there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u.

正确包含”表示_从不绑定自身,因此它永远不会扩展为x => x。在上一个示例中,_.toString正确包含_,因此满足上述两个条件。