什么时候在Scala中强制使用分号?

Mox*_*Mox 2 syntax scala semicolon-inference

我正在学习如何在Scala中编程,并被告知Scala中的分号是可选的.因此,考虑到这一点,我尝试使用以下嵌套的代码块,它没有半冒号.但是,它会在Scala REPL中引发错误

scala> { val a = 1
 | {val b = a * 2
 | {val c = b + 4
 | c}
 | }
 | }
<console>:17: error: Int(1) does not take parameters
   {val b = a * 2
Run Code Online (Sandbox Code Playgroud)

半结肠的样本工作得非常好.

scala> { val a = 1;
 | { val b = a*2;
 | { val c = b+4; c}
 | }
 | }
res22: Int = 6
Run Code Online (Sandbox Code Playgroud)

因此,在我看来,半结肠不是真正可选的,在某些情况下是强制性的.请问在什么情况下半结肠是强制性的?

And*_*kin 6

我将尝试从你的例子中提取精华.

请考虑以下代码段:

{ val x = 1 { val y = 2 } }
Run Code Online (Sandbox Code Playgroud)

对于编译器来说,它看起来像语法糖

{ val x = 1.apply({ val y = 2 }) }
Run Code Online (Sandbox Code Playgroud)

但是该对象1没有apply采用块的方法,因此编译器会产生错误:

错误:Int(1)不接受参数

  { val x = 1 { val y = 2 } }
              ^
Run Code Online (Sandbox Code Playgroud)

对比这个

object I { def apply(a: => Any): Unit = () }
{ val x = I { val y = 2 } }
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为I现在确实有一个apply方法.

为了使这两种情况之间的区别更容易一些,编译器在第一种情况下需要分号.

现在有人可能想知道为什么它之间val x = 1{换行和未转换为推断的分号.我认为规范中的相关引用将是这个(1.2换行符)(枚举的大多数部分省略([...]),强调我的):

Scala语法[...]包含可选nl令牌但不接受分号的作品.这导致其中一个位置换行不终止表达式或语句.这些职位可归纳如下:

[...]

  • 在开口括号 '{' 前面,如果该括号是当前陈述或表达的合法延续,

    [...]

请注意,此引用仅涵盖具有单个可选换行符的情况.它不适用于两个或多个连续的换行符,例如

scala> {
     |   val x = 1
     | 
     |   { val y = 2 }
     | }
Run Code Online (Sandbox Code Playgroud)

是有效的,并被{ val y = 2 }解析为单独的表达式.

动机是允许嵌入式DSL使用这样的语法糖:

MY_WHILE(x >= 0)
{
  println(x)
  x -= 1
}
Run Code Online (Sandbox Code Playgroud)

如果一个人必须将每个这样的MY_WHILE陈述括在另外一对圆括号中,那真的很奇怪,不是吗?


Bri*_*hon 5

添加到 Andrey 的答案中,您很少在惯用的 Scala 中编写这样的代码,但是,当您这样做时,您应该使用locally

{
  val a = 1
  locally {
    val b = a * 2
    locally {
      val c = b + 4
      c
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这个案例正是locally存在的原因。