【问题标题】:Multiline function literal as arguments in Scala多行函数文字作为 Scala 中的参数
【发布时间】:2012-12-02 01:43:27
【问题描述】:

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

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
}

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

【问题讨论】:

    标签: scala function-literal


    【解决方案1】:

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

    函数字面量或匿名函数 (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 => ... } 在 Block 的 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
    

    【讨论】:

    • 这是我正在寻找的解释。此外,除了您强调的规范部分之外,还可以参考 Blocks (6.11) 部分以更好地理解。
    【解决方案2】:

    这是让 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 不是 Unit 的成员 可能原因:分号可能是 在“值 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 时,你会编写代码并阅读很多内容。

    干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      • 2018-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-20
      相关资源
      最近更新 更多