Scala 3 通过新的控制结构和重要的缩进语法扩展了 Scala 语言的语法。两者都是可选的,因此 Scala 2 代码样式在 Scala 3 中仍然完全有效。
控制结构的新语法使得可以编写 if
表达式的条件、while
循环的条件或 for
表达式的生成器,而无需使用括号。
重要的缩进语法使得在许多情况下不需要大括号 {...}
:类和方法体、if
表达式、match
表达式等等。你可以在 Scala 3 参考网站的 可选大括号 页面中找到完整描述。
手动将现有的 Scala 代码转换为新语法既乏味又容易出错。在本章中,我们将展示如何使用编译器自动将你的代码从经典的 Scala 2 样式重写为新样式,反之亦然。
语法重写选项
让我们从展示编译器选项开始,我们有这些选项来实现我们的目标。如果我们简单地键入 scalac
在命令行上,它会打印出我们可用的所有选项。出于我们的目的,我们将使用以下五个选项
前四个选项中的每一个都对应一个特定的语法
语法 | 选项 |
---|---|
新控制结构 | -new-syntax |
旧控制结构 | -old-syntax |
语法 | 编译器选项 |
---|---|
显著缩进 | -indent |
经典大括号 | -noindent |
正如我们将在进一步的细节中看到,这些选项可以与 -rewrite
选项结合使用,以自动将特定语法转换为特定语法。让我们看看它如何在一个小示例中工作。
新语法重写
给定以下用 Scala 2 样式编写的源代码。
case class State(n: Int, minValue: Int, maxValue: Int) {
def inc: State =
if (n == maxValue)
this
else
this.copy(n = n + 1)
def printAll: Unit = {
println("Printing all")
for {
i <- minValue to maxValue
j <- 0 to n
} println(i + j)
}
}
我们将能够通过两个步骤自动将其移至新语法:首先使用新的控制结构重写 (-new-syntax -rewrite
),然后使用显著缩进重写 (-indent -rewrite
)。
该
-indent
选项不适用于经典控制结构。因此,请确保按正确的顺序运行这两个步骤。
不幸的是,编译器无法同时应用这两个步骤:
-indent -new-syntax -rewrite
。
新控制结构
我们可以使用 -new-syntax -rewrite
选项,方法是将它们添加到我们的构建工具中 scalac 选项的列表中。
// build.sbt, for Scala 3 project
scalacOptions ++= Seq("-new-syntax", "-rewrite")
编译代码后,结果如下
case class State(n: Int, minValue: Int, maxValue: Int) {
def inc: State =
if n == maxValue then
this
else
this.copy(n = n + 1)
def printAll: Unit = {
println("Printing all")
for
i <- minValue to maxValue
j <- 0 to n
do println(i + j)
}
}
请注意,括号周围的 n == maxValue
消失了,大括号周围的 i <- minValue to maxValue
和 j <- 0 to n
生成器也消失了。
显著缩进语法
完成此首次重写后,我们可以使用重要的缩进语法来移除剩余的花括号。为此,我们将 -indent
选项与 -rewrite
选项结合使用。这将引导我们进入以下版本
case class State(n: Int, minValue: Int, maxValue: Int):
def inc: State =
if n == maxValue then
this
else
this.copy(n = n + 1)
def printAll: Unit =
println("Printing all")
for
i <- minValue to maxValue
j <- 0 to n
do println(i + j)
返回经典语法
从代码示例的最新状态开始,我们可以向后移动到其初始状态。
让我们在保留新控制结构的同时使用花括号重写代码。在使用 -no-indent -rewrite
选项进行编译后,我们将获得以下结果
case class State(n: Int, minValue: Int, maxValue: Int) {
def inc: State =
if n == maxValue then
this
else
this.copy(n = n + 1)
def printAll: Unit = {
println("Printing all")
for {
i <- minValue to maxValue
j <- 0 to n
}
do println(i + j)
}
}
使用 -old-syntax -rewrite
再进行一次重写,将我们带回到原始 Scala 2 风格的代码。
通过此最后一次重写,我们已经完成了一个完整的循环。
在语法版本中循环时格式丢失
当使用 scalafmt 等格式化工具对代码应用自定义格式化时,在不同的 Scala 3 语法变体之间来回循环可能会在完成一个完整循环时导致差异。
强制执行特定语法
可以在单个代码库中混合使用旧语法和新语法。虽然我们建议不要这样做,因为它会降低可读性并使代码更难维护。更好的方法是选择一种样式并将其始终如一地应用于整个代码库。
-no-indent
、-new-syntax
和 -old-syntax
可用作独立选项来强制执行一致的语法。
例如,使用 -new-syntax
选项时,当编译器遇到 if
条件周围的括号时,它会发出错误。
-indent
语法始终是可选的,编译器无法强制执行它。