我曾经试图写过这方面的内容,但最终放弃了,因为规则有些模糊。基本上,你需要掌握它。
也许最好集中精力在大括号和小括号可以互换的地方:当传递参数给方法调用时。如果方法只期望一个参数,则可以将大括号替换为小括号。例如:
List(1, 2, 3).reduceLeft{_ + _}
List{1, 2, 3}.reduceLeft(_ + _)
然而,要更好地理解这些规则,还有更多需要了解的内容。
使用圆括号增强编译检查
Spray的作者建议使用圆括号,因为它们可以提供更严格的编译检查。特别是对于像Spray这样的领域专用语言。通过使用圆括号,您告诉编译器它只应该编译一行代码;因此,如果意外输入两行或更多行代码,编译器将会报错。但是,使用花括号却不是这种情况——例如,如果您忘记在某个地方添加运算符,您的代码会编译通过,但得到的结果可能与预期不同,并且可能难以找出错误。以下示例虽有点牵强(因为表达式是纯洁的,至少会给出警告),但可以说明这一点:
method {
1 +
2
3
}
method(
1 +
2
3
)
第一个代码段编译成功,第二个代码段会报错:
error: ')' expected but integer literal found
。原作者想要写的是
1 + 2 + 3
。
对于含默认参数的多参数方法,有人认为使用括号可以避免因忘记用逗号分隔而导致的错误。
关于冗长程度的问题,一个常被忽视的重要点是,使用花括号会不可避免地导致冗长的代码,因为
Scala样式指南明确规定,闭合花括号必须位于其自己的一行上:
...闭合大括号在函数最后一行之后占据一行。
许多自动格式化程序,比如IntelliJ中的程序,会自动为您执行此重新格式化。所以尽量在可能的情况下使用圆括号。
在使用中缀符号表示法时,例如
List(1,2,3) indexOf (2)
如果只有一个参数,你可以省略括号并将其写成
List(1, 2, 3) indexOf 2
。但在点符号表示法中不适用。
还要注意的是,当您有一个单参数且为多令牌表达式的情况,例如
x + 2
或
a => a % 2 == 0
,您必须使用括号来表示表达式的边界。
因为有时可以省略括号,所以有时元组需要额外的括号,比如
((1, 2))
,有时外部的括号可以省略,比如
(1, 2)
。这可能会导致混淆。
Scala支持类似于以下示例的函数和偏函数字面量语法:
{
case pattern if guard => statements
case pattern => statements
}
你可以在使用 match
和 catch
关键字时使用case
语句:
object match {
case pattern if guard => statements
case pattern => statements
}
try {
block
} catch {
case pattern if guard => statements
case pattern => statements
} finally {
block
}
如果你想使用case
语句,就必须在花括号中使用它们,因为在任何其他上下文中都不能使用。如果你想知道什么区分函数和部分函数文字,答案是:上下文。如果Scala需要一个函数,则会得到一个函数。如果期望一个部分函数,那么你将得到一个部分函数。如果两者都被期望,它会产生关于歧义的错误。
表达式和块
可以使用括号来创建子表达式。花括号可以用来创建代码块(这不是函数文字,所以小心不要试图像使用函数文字一样使用它)。代码块由多个语句组成,每个语句都可以是导入语句、声明或表达式。其格式如下:
{
import stuff._
statement ;
statement ; statement
var x = 0
while (x < 10) { x += 1 }
(x % 5) + 1
}
( expression )
所以,如果你需要声明、多个语句、import
或者其他类似的东西,你就需要用花括号来包裹。因为表达式是一种语句,所以括号可能会出现在花括号中。但有趣的是,代码块也是表达式,因此您可以将它们用在表达式的任何位置:
( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1
因此,既然表达式是语句,代码块也是表达式,那么下面的所有内容都是有效的:
1 // literal
(1) // expression
{1} // block of code
({1}) // expression with a block of code
{(1)} // block of code with an expression
({(1)}) // you get the drift...
它们不可互换的情况
基本上,你不能在任何其他地方将{}
替换为()
或反之亦然。例如:
while (x < 10) { x += 1 }
这不是一个方法调用,所以你不能以任何其他方式编写它。嗯,你可以在 condition
的括号中间放置花括号,也可以在代码块的花括号中使用括号:
while ({x < 10}) { (x += 1) }
{}
- 一切都应该是一个单一的纯表达式。 - samthebestList{1, 2, 3}.reduceLeft(_ + _)
是无效的时候,是指它有语法错误吗?但我发现这段代码可以编译。我把我的代码放在了这里。 - calvinList(1, 2, 3)
,而不是List{1, 2, 3}
。然而,在 Scala 的当前版本(2.13)中,这会导致一个不同的错误信息(意外的逗号)。你可能需要回到 2.7 或 2.8 版本才能得到原始的错误信息。 - Daniel C. Sobral