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

jaf*_*don 15 scala function-literal

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

val fl = (x: Int) => {
  println("Add 25 to "+x)
  x + 25
}
Run Code Online (Sandbox Code Playgroud)

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

所以对于给定的函数f,

def f( fl: Int => Int ) {
  println("Result is "+ fl(5))
}
Run Code Online (Sandbox Code Playgroud)

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

f( x=> {
  println("Add 25 to "+x)
  x + 25
})
-------------------------
Add 25 to 5
Result: 30
Run Code Online (Sandbox Code Playgroud)

或者在函数调用中使用花括号而不是括号时,可以从函数文本中删除内部花括号.所以下面的代码也可以,

f{ x=>
  println("Add 25 to "+x)
  x + 25
}
Run Code Online (Sandbox Code Playgroud)

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

som*_*ytt 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
Run Code Online (Sandbox Code Playgroud)


wle*_*eao 11

这是让Scala对我很漂亮的事情之一.

你问题的简单答案是:

圆括号()用于单行构造.例如,这有效:

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

  f(
   x =>
    x + 25)

  f(x => x + 25) // single line
Run Code Online (Sandbox Code Playgroud)

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

 f { 
   x =>
     println("Add 25 to " + x)
     x + 25
 }   
Run Code Online (Sandbox Code Playgroud)

但是这段代码不起作用:

f ( 
  x =>
    println("Add 25 to " + x)
    x + 25
)
Run Code Online (Sandbox Code Playgroud)

编译器抱怨以下消息:

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

如果添加分号,则会出现由不匹配的括号引起的语法错误.

如果您尝试这样做:

f { x => println("Add 25 to " + x) x + 25 }
Run Code Online (Sandbox Code Playgroud)

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

value x is not a member of unit
Run Code Online (Sandbox Code Playgroud)

你是否得到了他正试图找到x作为单位的成员.喜欢:

f { println("Add 25 to " + x).x.+(25) }
Run Code Online (Sandbox Code Playgroud)

这显然是错的.

如果你添加内花括号,像这样:

f ( 
  x => {
    println("Add 25 to " + x)
    x + 25 
  }
)
Run Code Online (Sandbox Code Playgroud)

这也可以,但你仍然有一个多线语句,通过使用花括号来表示.所以编译器知道你想要的是先打印然后再添加25到x.

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

干杯!