多线函数文字作为Scala中的参数

时间:2012-12-14 03:24:15

标签: scala function-literal

我总是想知道为什么有时使用函数文字我们可以忽略大括号,即使对于多个语句也是如此。为了说明这一点,多行函数文字的语法是用大括号括起语句。像这样,

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
}

上面的代码更具可读性,我注意到很多例子都使用这种语法。但是,是否有任何我可能错过的特殊规则,以解释为什么这样做符合预期?

2 个答案:

答案 0 :(得分:24)

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

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

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

当你致电f(g)时,g是一个Expr,所以作为一个函数文字,x => Expr。 Expr可以是BlockExpr,x => { ... }

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

在这里,很明显anon func位于一个块的底部:

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

答案 1 :(得分:11)

这是让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时,你会编写代码并阅读很多内容。

干杯!