在Scala中开发时,我似乎经常遇到空白问题,这会对代码的含义产生意想不到的影响。
最近,我在尝试编写一个多行布尔表达式时遇到了麻烦,其中断行似乎导致编译错误,即
(oneVeryLongExpression < anotherVeryLongExpression) || ((a == b) && c);
...编译得很好,但是,如果因为这些很长的表达式而我很想分割线......
(oneVeryLongExpression < anotherVeryLongExpression)
|| ((a == b) && c);
......它没有编译,这让我感到意外。
我发现我可以通过在整个表达式周围添加一组额外的括号来解决这个问题:
((oneVeryLongExpression < anotherVeryLongExpression)
|| ((a == b) && c));
...但我仍然想了解为什么Scala需要这个提示来忽略换行符。
在向另一个方向发展时我也遇到了问题:我偶尔会将一个中等大小的Scala代码块转换为一组单行代码片段,以便将每个代码片段作为单行输入到基于Scala的shell中不接受多行输入。
这是一个for-each的示例,我需要能够在我的shell中作为单行输入运行(对于那些对我正在做的事感到好奇的人,我正在查看我的图表用于等式检查的软件,其中任一侧的变量类型属于特定类型,以查找应该使用x.equals(y)
而不是x == y
的地方):
equalityChecks.foreach { node => {
var lhsFound = false;
var rhsFound = false;
breakable {
node.inEdges().foreach { edge => {
if (nodesOfTypeT.contains(edge.originNode())) {
if (edge.tagged(leftOperand)) {
lhsFound = true;
};
if (e.taggedWith(rightOperand)) {
rhsFound = true;
};
if (lhsFound && rhsFound) {
doublyReachable.add(n);
break; /* skip the rest of the edges and process next node */
};
}
}}
};
}};
请注意breakable
块和三个if
块之后的额外分号,至少其中一些是必需的,以便在删除换行符时保留代码的含义;没有它们,它就不会编译。
在什么情况下换行在Scala中具有语义含义?在添加或删除换行符之前,如何判断它是否会改变代码的含义?
答案 0 :(得分:5)
(oneVeryLongExpression < anotherVeryLongExpression)
是scala中的正确表达式。当编译器遍历代码并满足此表达式并且在同一行中没有任何内容时,它会将其报告为正确的表达式。然后下一行|| ((a == b) && c);
变得意外并产生错误。在这种情况下,您使用括号使编译器了解多行表达式是正确的。您也可以在第一行留下||
,使第一行无效表达式:
(oneVeryLongExpression < anotherVeryLongExpression) ||
((a == b) && c);
scala REPL也接受多行输入。只需输入:paste
命令即可输入任何内容。按ctrl-D
完成
对于分号,scala中很少需要它们。我认为你需要在for-comprehensions中或者如果你将几个单独的表达式放在一行中。在您的示例中,node => ...
由三个表达式组成:
var lhsFound = false
,var rhsFound = false
和breakable {...}
可分解形成一个单独的大表达式,但它也是由几个if语句组成的,因此您需要将它们分开,因为它们是单独的表达式。当然,这仅适用于您将所有内容都作为单线程的情况。我仍然认为你不应该把这些分号 - 只需在REPL中使用粘贴模式。
我发现自己只在for-comprehensions或短模式匹配(通常是部分函数)中使用分号,我希望它们是单行的
P.S。 }
之前的分号始终是可选的,因为它不会分隔表达式。我相信在= true
和break
之后的if中的代码中的分号可以被删除。如果您将所有这些代码放在一行中,那么所有其他代码都是正确的