scala中何时使用分号?

问题描述 投票:1回答:2

我正在学习如何在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

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

scala> { val a = 1;
 | { val b = a*2;
 | { val c = b+4; c}
 | }
 | }
res22: Int = 6

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

scala syntax semicolon-inference
2个回答
6
投票

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

请考虑以下代码段:

{ val x = 1 { val y = 2 } }

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

{ val x = 1.apply({ val y = 2 }) }

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

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

  { val x = 1 { val y = 2 } }
              ^

对比这个

object I { def apply(a: => Any): Unit = () }
{ val x = I { val y = 2 } }

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

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

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

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

[...]

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

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

scala> {
     |   val x = 1
     | 
     |   { val y = 2 }
     | }

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

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

MY_WHILE(x >= 0)
{
  println(x)
  x -= 1
}

如果必须将每个这样的MY_WHILE语句附加到另外一对圆括号中,那真的很奇怪,不是吗?


4
投票

除了安德烈的答案之外,很少你在惯用的Scala中编写这样的代码,但是,当你这样做时,你应该使用locally

{
  val a = 1
  locally {
    val b = a * 2
    locally {
      val c = b + 4
      c
    }
  }
}

这种情况正是locally存在的原因。

© www.soinside.com 2019 - 2024. All rights reserved.