我正在学习如何在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
因此,在我看来,半结肠不是真正可选的,在某些情况下是强制性的。请问在什么情况下半结肠是强制性的?
我将尝试从你的例子中提取精华。
请考虑以下代码段:
{ 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
语句附加到另外一对圆括号中,那真的很奇怪,不是吗?
除了安德烈的答案之外,很少你在惯用的Scala中编写这样的代码,但是,当你这样做时,你应该使用locally
:
{
val a = 1
locally {
val b = a * 2
locally {
val c = b + 4
c
}
}
}
这种情况正是locally
存在的原因。