简体   繁体   English

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

[英]Multiline function literal as arguments in Scala

I always wondered why sometimes with function literals we can ignore the curly brace even for multiple statements. 我总是想知道为什么有时使用函数文字我们可以忽略大括号,即使是多个语句。 To illustrate this, the syntax for a multiline function literal is to enclose the statements with curly braces. 为了说明这一点,多行函数文字的语法是用大括号括起语句。 Like so, 像这样,

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

However, when you pass it to a single-argument function, you can ignore the required curly brace for the function literal. 但是,当您将其传递给单参数函数时,您可以忽略函数文字所需的大括号。

So for a given function f, 所以对于给定的函数f,

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

You can call f() like this, 你可以像这样调用f(),

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

Or when you use curly braces instead of parenthesis in the function call, you can remove the inner curly braces from the function literal. 或者在函数调用中使用花括号而不是括号时,可以从函数文字中删除内部花括号。 So the following code will also work, 所以下面的代码也可以,

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

The above code is more readable and I notice that a lot of examples use this syntax. 上面的代码更具可读性,我注意到很多例子都使用这种语法。 However, is there any special rule that I may have missed, to explain why this is working as intended? 但是,是否有任何我可能错过的特殊规则,以解释为什么这样做符合预期?

There are just a couple of simple syntax rules. 只有几个简单的语法规则。 The appendix of the spec is worth perusing. 该规范的附录值得细读。

A function literal or anonymous function (6.23) will look like x => Expr or x => Block depending on whether the context is an Expr or a ResultExpr, respectively. 函数文字或匿名函数(6.23)看起来像x => Exprx => Block具体取决于上下文分别是Expr还是ResultExpr。

A function application (6.6) will look like f(Expr, Expr) or f BlockExpr , ie, f{ Block } . 函数应用程序(6.6)看起来像f(Expr, Expr)f BlockExpr ,即f{ Block } That is, a BlockExpr is just a sequence of block statements inside {...} . 也就是说,BlockExpr只是{...}的一系列块语句。

When you call f(g) , then g is an Expr, so as a function literal, x => Expr . 当你调用f(g) ,g是一个Expr,所以作为函数文字, x => Expr The Expr can be a BlockExpr, x => { ... } . Expr可以是BlockExpr, x => { ... }

When you call f{ Block } , then f { x => ... } has the function literal in ResultExpr of a Block (which is just a sequence of statements, no braces required). 当你调用f{ Block }f { x => ... }在块的ResultExpr中有函数文字(这只是一系列语句,不需要大括号)。

Here, it's obvious that the anon func is at the bottom of a block: 在这里,很明显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

This is one of the things that make Scala beautiful to me. 这是让Scala对我很漂亮的事情之一。

The simple answer to your question is: 你问题的简单答案是:

Parentheses ( ) are meant for single line constructions. 圆括号()用于单行构造。 For instance, this works: 例如,这有效:

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

  f(
   x =>
    x + 25)

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

and curly braces { } are meant for multiline statements. 和花括号{}用于多行语句。 For instance, this works: 例如,这有效:

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

but this code doesn't work: 但是这段代码不起作用:

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

The compiler complains with the following message: 编译器抱怨以下消息:

value x is not a member of Unit possible cause: maybe a semicolon is missing before `value x'? 值x不是单位可能原因的成员:可能在“值x”之前缺少分号?

If you add the semicolon, you'll get a syntax error caused by the unmatched parenthesis. 如果添加分号,则会出现由不匹配的括号引起的语法错误。

If you try to do this: 如果您尝试这样做:

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

The compiler will get back to you with the message: 编译器将通过以下消息回复您:

value x is not a member of unit

Do you get that he is trying to find x as a member of unit. 你是否得到了他正试图找到x作为单位的成员。 Like: 喜欢:

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

Which is clearly wrong. 这显然是错的。

If you add the inner curly braces, Like this: 如果你添加内花括号,像这样:

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

This will also work, but you still have a multiline statement that is signaled by the usage of the curly braces. 这也可以,但你仍然有一个多线语句,通过使用花括号来表示。 So the compiler knows what you want there is to first print and then add 25 to x. 所以编译器知道你想要的是先打印然后再添加25到x。

I've been bitten before by those subtleties. 我之前被这些微妙之处所困扰。 Ever since, I've been paying attention to the way I code with those, because you'll code and read a lot of this when you're mainly using maps, flatMaps, foreachs, fors and currying. 从那以后,我一直在关注我用这些编码的方式,因为当你主要使用map,flatMaps,foreachs,fors和currying时,你会编写代码并阅读很多内容。

Cheers! 干杯!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM