17

我一直想知道为什么有时使用函数文字我们可以忽略大括号,即使是多个语句。为了说明这一点,多行函数字面量的语法是用花括号将语句括起来。像这样,

val fl = (x: Int) => {
  println("Add 25 to "+x)
  x + 25
}

但是,当您将其传递给单参数函数时,您可以忽略函数文字所需的大括号。

所以对于给定的函数 f,

def f( fl: Int => Int ) {
  println("Result is "+ fl(5))
}

你可以像这样调用 f(),

f( x=> {
  println("Add 25 to "+x)
  x + 25
})
-------------------------
Add 25 to 5
Result: 30

或者,当您在函数调用中使用大括号而不是括号时,您可以从函数文字中删除内部大括号。所以下面的代码也可以工作,

f{ x=>
  println("Add 25 to "+x)
  x + 25
}

上面的代码更具可读性,我注意到很多示例都使用这种语法。但是,是否有任何我可能遗漏的特殊规则来解释为什么它按预期工作?

4

2 回答 2

29

只有几个简单的语法规则。该规范的附录值得细读。

函数文字或匿名函数 (6.23) 看起来像x => Exprx => Block取决于上下文是分别是 Expr 还是 ResultExpr。

函数应用程序(6.6)看起来像f(Expr, Expr)or f BlockExpr,即f{ Block }。也就是说,一个 BlockExpr 只是一个内部的块语句序列{...}

当您调用 时f(g),g 是一个 Expr,因此作为函数文字,x => Expr. Expr 可以是 BlockExpr x => { ... },.

当您调用时f{ Block }f { x => ... }在 Block 的 ResultExpr 中有函数文字(这只是一系列语句,不需要大括号)。

在这里,很明显 anon 函数位于块的底部:

scala> def m(x: Int=>Int) = x(5)
m: (x: Int => Int)Int

scala> m {
     | val y = 7
     | x => // no brace
     | x+y+1
     | }
res0: Int = 13
于 2012-12-14T06:40:29.033 回答
14

这是让 Scala 对我来说很美的原因之一。

您的问题的简单答案是:

括号 ( ) 用于单行结构。例如,这有效:

  def f(fl: Int => Int) {
    println("Result is " + fl(5))
  }

  f(
   x =>
    x + 25)

  f(x => x + 25) // single line

花括号 { } 用于多行语句。例如,这有效:

 f { 
   x =>
     println("Add 25 to " + x)
     x + 25
 }   

但这段代码不起作用:

f ( 
  x =>
    println("Add 25 to " + x)
    x + 25
)

编译器抱怨以下消息:

值 x 不是单元的成员 可能原因:可能在“值 x”之前缺少分号?

如果添加分号,则会出现由不匹配的括号导致的语法错误。

如果您尝试这样做:

f { x => println("Add 25 to " + x) x + 25 }

编译器将通过以下消息回复您:

value x is not a member of unit

你知道他正试图找到 x 作为单位的成员。像:

f { println("Add 25 to " + x).x.+(25) }

这显然是错误的。

如果添加内部花括号,如下所示:

f ( 
  x => {
    println("Add 25 to " + x)
    x + 25 
  }
)

这也可以,但是您仍然有一个多行语句,它通过使用花括号来表示。所以编译器知道你想要什么是先打印然后将 25 添加到 x。

我以前被这些微妙之处咬过。从那以后,我一直在关注我使用这些代码的方式,因为当你主要使用地图、flatMaps、foreachs、fors 和 currying 时,你会编写代码并阅读很多内容。

干杯!

于 2012-12-14T04:34:31.683 回答