Scala 3 迁移指南

语法更改

语言

Scala 3 引入了可选大括号语法和新的控制结构语法。它以对现有语法进行一些最小的限制为代价。

其他语法更改旨在使语法不那么令人惊讶且更一致。

值得注意的是,大多数更改可以在 Scala 3 迁移编译期间自动处理。

不兼容性 Scala 2.13 Scala 3 迁移重写 Scalafix 规则
受限关键字    
过程语法 弃用
lambda 参数周围的括号    
传递参数的左大括号缩进    
错误的缩进      
_ 作为类型参数      
+- 作为类型参数      

受限关键字

Scala 3 关键字列表可在 此处 找到。常规关键字不能用作标识符,而关键字不受限制。

对于从 Scala 2.13 迁移到 Scala 3 的问题,只有新的常规关键字的子集存在问题。它由以下内容组成

  • enum
  • export
  • given
  • then
  • =>>
  • ?=>

例如,以下代码段可以用 Scala 2.13 编译,但不能用 Scala 3 编译。

object given { // In Scala 3, Error: given is now a keyword.
  val enum = ??? // In Scala 3, Error: enum is now a keyword.

  println(enum) // In Scala 3, Error: enum is now a keyword.
}

Scala 3 迁移编译 将代码重写为

-object given {
+object `given` {
-  val enum = ???
+  val `enum` = ???

-  println(enum)
+  println(`enum`)
 }

过程语法

过程语法已弃用一段时间,并且在 Scala 3 中已删除。

以下代码段现在是非法的

object Bar {
  def print() { // In Scala 3, Error: Procedure syntax no longer supported; `: Unit =` should be inserted here.
    println("bar")
  }
}

Scala 3 迁移编译 将代码重写为。

 object Bar {
-  def print() {
+  def print(): Unit = {
     println("bar")
   }
 }

Lambda 参数周围的括号

当后面跟着其类型时,现在需要将 lambda 的参数括在括号中。以下代码段无效。

val f = { x: Int => x * x } // In Scala 3, Error: parentheses are required around the parameter of a lambda.

Scala 3 迁移编译 将代码重写为

-val f = { x: Int => x * x }
+val f = { (x: Int) => x * x }

传递参数时的花括号缩进

在 Scala 2 中,可以通过将参数括在花括号中,在换行后传递参数。虽然有效,但 Scala 样式指南 不鼓励这种编码风格,并且在 Scala 3 中不再支持。

test("my test")
{ // In Scala 3, Error: This opening brace will start a new statement.
  assert(1 == 1)
}

Scala 3 迁移编译器 缩进块的第一行。

 test("my test")
-{
+  {
   assert(1 == 1)
 }

此迁移规则也适用于其他模式,例如在换行后优化类型。

 type Bar = Foo
-{
+  {
   def bar(): Int
 }

一个更好的解决方案是编写

-test("my test")
-{
+test("my test") {
   assert(1 == 1)
 }

错误的缩进

Scala 3 编译器现在需要正确的缩进。以下代码段在 Scala 2.13 中编译,但由于缩进而无法再编译。

def bar: (Int, Int) = {
  val foo = 1.0
  val bar = foo // [E050] In Scala 3, type Error: value foo does not take parameters.
    (1, 1)
} // [E007] In Scala 3, type Mismatch Error: Found Unit, Required (Int, Int).

必须修复缩进。

 def bar: (Int, Int) = {
   val foo = 1.0
   val bar = foo
-    (1, 1)
+  (1, 1)
 }

可以通过使用 Scala 格式化工具(例如 scalafmtIntelliJ Scala 格式化工具)来防止这些错误。请注意,这些工具可能会更改项目的整个代码样式。

_ 作为类型参数

在 Scala 2.13 中允许将 _ 标识符用作类型参数,即使它从未在 Scala 2 规范中提及。它与上下文绑定结合使用,在 fastparse 的 API 中用于声明隐式参数。

def foo[_: Foo]: Unit = ???

此处,方法 foo 采用类型参数 _ 和类型为 Foo[_] 的隐式参数,其中 _ 指的是类型参数,而不是通配符符号。

Martin Odersky 将此模式描述为“scalac 编译器错误的巧妙利用”(来源)。

Scala 3 编译器不再允许此模式

-- [E040] Syntax Error: src/main/scala/anonymous-type-param.scala:4:10
4 |  def foo[_: Foo]: Unit = ()
  |          ^
  |          an identifier expected, but '_' found

解决方案是为参数提供一个有效的标识符名称,例如 T。这不会破坏二进制兼容性。

-def foo[_: Foo]: Unit = ???
+def foo[T: Foo]: Unit = ???

+- 作为类型参数

+- 在 Scala 3 中不是类型参数的有效标识符,因为它们是为方差注释保留的。

您不能再编写 def foo[+]def foo[-]

-- Error: src/main/scala/type-param-identifier.scala:2:10 
2 |  def foo[+]: +
  |          ^
  |          no `+/-` variance annotation allowed here

解决方案是选择另一个有效的标识符,例如 T

但是,+- 仍然是通用的有效类型标识符。您可以编写 type +

此页面的贡献者