Scala 编码标准:在同一行上的大括号

  • 本文关键字:一行 标准 编码 Scala scala
  • 更新时间 :
  • 英文 :


scala编码标准指出

从技术上讲,Scala 的解析器确实支持 GNU 风格的符号,在声明后面的行上有左大括号。但是,由于分号推理的实现方式,解析器在处理这种样式时并不是非常可预测的。只需遵循上面演示的卷曲支架惯例,就可以节省许多头痛。

我看过了,我找不到任何真实的例子。谁能用例子解释这背后的原因?有没有人在新行上使用大括号时遇到问题?

考虑这个表达式:

someElement
{
// Some code
}

这是如何解释的?它是一个表达式(例如值或没有参数的函数调用)后跟括在大括号内的块语句吗?还是带有大括号括住单个参数的函数调用?

如果 Scala 没有分号推理——也就是说,如果Scala要求分号以与Java相同的方式表示语句的结尾——那么这两者可以很容易地区分,因为前者需要在第一行的末尾使用分号。但是,Scala解析器必须推断分号需要在哪里才能理解代码,有时它会出错。(根据上下文的不同,这两种解释都是有效的,并且 Scala解析器并不总是能够自行解决歧义。

例如,假设someElement是一个带有by name参数的函数。如果您尝试在Scala REPL中调用它,打算将参数(在大括号内)放在另一行上,您会发现单独输入someElement会导致错误:

> scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.
scala> def someElement(x: => Int): Int = {
|   // Do something...
|   x
| }
someElement: (x: => Int)Int
scala> someElement
<console>:13: error: missing argument list for method someElement
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `someElement _` or `someElement(_)` instead of `someElement`.
someElement
^

也就是说,您甚至无法进入牙套。但是,如果您输入以下内容,则没问题:

scala> someElement {
|   10
| }
res0: Int = 10

但是,如果someElement是一个值呢?现在我们在REPL中看到了这一点:

scala> val someElement = 5
someElement: Int = 5
scala> someElement
res1: Int = 5
scala> {
|   5
| }
res2: Int = 5

现在,REPL接受相同的代码,在不同的行上,作为两个不同的表达式。

让我们变得非常模棱两可。假设someElement是一个值,但它现在是对接受单个参数的函数的引用。让我们看看可能的解释:

scala> def square(a: Int) = a * a
square: (a: Int)Int
scala> val someElement = square _
someElement: Int => Int = $$Lambda$1034/1609754699@74abbb
scala> someElement
res3: Int => Int = $$Lambda$1034/1609754699@74abbb
scala> {
|   5
| }
res4: Int = 5

也就是说,它被视为两个单独的语句:一个值,后跟一个块语句。然而:

scala> someElement {
|   5
| }
res5: Int = 25

被视为参数为 5 的square调用。

Scala编译器比REPL聪明一点,因为它可以一次看到所有代码,并且会尝试通过查看哪种替代方案最有意义来解决歧义,但它的解释可能并不总是与您的解释相匹配。

因此,如您所见,将左大括号放在同一行(如果两个表达式链接)会使关系明确并消除歧义。或者,如果您希望将表达式明确地解析为单独的语句,请在第一行后添加分号。

(恕我直言,分号推断是斯卡拉致命弱点之一。

最新更新