【问题标题】:Omitting parenthesis省略括号
【发布时间】:2013-06-20 10:05:04
【问题描述】:

这是 Scala 代码

 #1
 def method1 = {
   map1.foreach({
    case(key, value) => { println("key " + key + " value " + value) }
   })
}

 #2
 def method1 = {
   map1.foreach{
    case(key, value) => { println("key " + key + " value " + value) }
   }
}

这对我来说几乎是数字,但我想更清楚地说明:为什么在这种情况下可以省略括号?

【问题讨论】:

  • 您甚至可以进一步删除一些大括号:def method1 = map1.foreach { case (key, value) => println("key " + key + " value " + value) }

标签: scala


【解决方案1】:

可以在 Scala 中总是用花括号交换方法参数括号。例如

def test(i: Int) {}

test { 3 }

此基础是参数表达式的定义,在Scala Language Specification (SLS) 的第 6.6 节中涵盖:

ArgumentExprs ::= ‘(’ [Exprs] ‘)’
                | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ’)’
                | [nl] BlockExpr

花括号被最后一种情况(块表达式)覆盖,本质上是‘{’ Block ‘}’(参见第 6 章 SLS 的开头)。

这不适用于条件表达式,if, (§6.16 SLS) 和 while 循环表达式 (§6.17 SLS),但它适用于 for 推导式 (§6.19 SLS),有点像不一致。

另一方面,模式匹配语句或模式匹配匿名函数字面量必须用花括号定义,例如{ case i: Int => i + i },此处不允许使用括号 (§8.5 SLS)。

在您的方法调用中,foreach 接受一个函数参数,因此您可以删除多余的括号或双括号:

List(1, 2).foreach({ case i => println(i) })
List(1, 2).foreach {{ case i => println(i) }}

List(1, 2).foreach { case i => println(i) }  // no reason to have double braces

在这种情况下,模式匹配并不能真正为您带来任何好处,您可以使用常规(非模式匹配)函数,因此以下方法也可以:

List(1, 2).foreach(i => println(i)) // §6.23 SLS - anonymous functions
List(1, 2).foreach(println)         // §6.26.2 / §6.26.5 - eta expansion

在您的情况下,Mapmap 方法将键和值的元组传递给函数,这就是您使用模式匹配(case 语句)来解构该元组的原因,因此您被绑定了有花括号。这比写作更好

map1.foreach(tup => println("key " + tup._1 + " value " + tup._2)

作为旁注,在模式匹配案例主体周围放置大括号被认为是不好的风格;即使正文跨越多行,它们也不是必需的。所以不是

case(key, value) => { println("key " + key + " value " + value) }

你应该写

case (key, value) => println("key " + key + " value " + value)

关于在 Scala 中使用大括号、圆点和圆括号的不同变体,in this blog post 存在一些争议(“不喜欢的部分”部分)。最后,你要决定哪种风格最好——这就是提倡“自以为是”与“非自以为是”语言的人们相互争斗的地方。

通常,当表达式跨越多行或有模式匹配时,您需要花括号。当调用具有多个参数列表的方法时,通常最后一个列表包含一个函数参数,所以你会很好看——当然是主观判断——语法:

val l = List(1, 2, 3)
l.foldLeft(0) {
  (sum, i) => sum + i
}

【讨论】:

  • 我想问题是为什么会这样:List(1).map {_+1},但List(1).map fList(1).map( case i => i ) - 不是。
  • @senia 前一种情况被作为块语句的参数表达式覆盖。第二种情况是无效的,因为您正试图进行“中途”中缀运算符调用(再次参见第 6 章 SLS)。中缀表达式是InfixExpr id [nl] InfixExpr,所以这里不能有句点。 List(1) map f 是一个有效的中缀调用。
  • 如果大括号是函数文字的一部分,则前一种情况和第二种情况相等。如果用大括号代替括号,那么前一种情况和第三种情况是相等的。那么它是哪一个?事实上,在这种情况下,大括号是圆括号 的替代品,功能文字解析不是上下文独立的。所以{case i => i} 等于{f}(而( case i => i) 不等于(f))。但是我找不到对应的文档。
  • f 不是函数字面量。它可能是一个持有函数的 value。那不一样。在val i = 3 中,3 是文字,但i 是一个值。福特野马是一辆汽车,但并非每辆车都是野马。参数表达式可以使用块表达式。但是模式匹配文字必须始终使用花括号。因此第三种情况无效。 {case i => i} 是模式匹配文字,{f} 不是(同样,f 是一个值)。
  • 谢谢!我认为ArgumentExprs 的定义类似于‘(’ [Exprs] ‘)’ | ‘{’ Expr ‘}’,但它就像‘(’ [Exprs] ‘)’ | BlockExpr。现在一切都清楚了。
猜你喜欢
  • 1970-01-01
  • 2018-08-06
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多