为了简化语言,某些功能已弃用。在 Scala 3 迁移编译期间,大多数这些更改都可以自动处理。
不兼容性 | Scala 2.13 | Scala 3 迁移重写 | Scalafix 规则 |
---|---|---|---|
符号文字 | 弃用 | ✅ | |
do -while 结构 |
✅ | ||
自动应用 | 弃用 | ✅ | ✅ |
值 eta 扩展 | 弃用 | ✅ | ✅ |
any2stringadd 转换 |
弃用 | ✅ | |
早期初始化程序 | 弃用 | ||
存在类型 | 功能警告 | ||
@specialized | 弃用 |
符号文字
符号文字语法在 Scala 2.13 中已弃用,并在 Scala 3 中删除。但 scala.Symbol
类仍然存在,因此每个字符串文字都可以安全地替换为 Symbol
的应用。
此代码段无法使用 Scala 3 编译
val values: Map[Symbol, Int] = Map('abc -> 1)
val abc = values('abc) // In Scala 3, Migration Warning: symbol literal 'abc is no longer supported
Scala 3 迁移编译将代码重写为
尽管 Symbol
类在过渡期间很有用,但请注意它已被弃用,并且将在未来版本中从 scala-library
中删除。建议您在第二步中将 Symbol
的每次使用替换为普通字符串文字 "abc"
或自定义专用类。
do
-while
结构
在 新控制语法 中,do
关键字已获得不同的含义。
为了避免混淆,传统的 do <body> while (<cond>)
构造已弃用。建议使用等效的 while ({ <body>; <cond> }) ()
(它可以进行交叉编译),或新的 Scala 3 语法 while { <body>; <cond> } do ()
。
以下代码段无法使用 Scala 3 编译。
do { // In Scala 3, Migration Warning: `do <body> while <cond>` is no longer supported
i += 1
} while (f(i) == 0)
Scala 3 迁移编译会将其重写为。
while ({ {
i += 1
} ; f(i) == 0}) ()
自动应用
自动应用是调用空括号方法(例如 def toInt(): Int
)的语法,无需传递空参数列表。它在 Scala 2.13 中已弃用,并在 Scala 3 中删除。
以下代码在 Scala 3 中无效
object Hello {
def message(): String = "Hello"
}
println(Hello.message) // In Scala 3, Migration Warning: method message must be called with () argument
Scala 3 迁移编译会将其重写为
自动应用在 Scala 3 参考文档的 此页面 中有详细介绍。
值 eta 扩展
Scala 3 引入了 自动 Eta 展开,它将弃用方法到值语法 m _
。此外,Scala 3 不再允许将值 eta 展开为零元函数。
因此,以下代码段在 Scala 3 中无效
val x = 1
val f: () => Int = x _ // In Scala 3, Migration Warning: The syntax `<function> _` is no longer supported;
Scala 3 迁移编译会将其重写为
any2stringadd
转换
隐式 Predef.any2stringadd
转换在 Scala 2.13 中已弃用,并在 Scala 3 中删除。
以下代码段在 Scala 3 中不再编译。
val str = new AnyRef + "foo" // In Scala 3, Error: value + is not a member of Object
必须显式应用到 String
的转换,例如使用 String.valueOf
。
此重写可以通过 scala/scala-rewrites
中的 fix.scala213.Any2StringAdd
Scalafix 规则应用。
早期初始化器
早期初始化器在 Scala 2.13 中已弃用,并在 Scala 3 中删除。它们很少使用,并且主要用于弥补 特征参数 的不足,而特征参数现在在 Scala 3 中受支持。
这就是为什么以下代码段在 Scala 3 中不再编译的原因。
trait Bar {
val name: String
val size: Int = name.size
}
object Foo extends {
val name = "Foo"
} with Bar
Scala 3 编译器生成两条错误消息
它建议使用特性参数,这将为我们提供
trait Bar(name: String) {
val size: Int = name.size
}
object Foo extends Bar("Foo")
由于 Scala 2.13 中没有特性参数,因此它不会进行交叉编译。如果您需要交叉编译解决方案,可以使用一个中间类,它将早期初始化的 val
和 var
作为构造函数参数。
Scala 2 中早期初始化程序的另一个用例是子类中的私有状态,它由超类的构造函数(通过覆盖的方法)访问
class Adder {
var sum = 0
def add(x: Int): Unit = sum += x
add(1)
}
class LogAdder extends {
private var added: Set[Int] = Set.empty
} with Adder {
override def add(x: Int): Unit = { added += x; super.add(x) }
}
可以通过将私有状态移动到嵌套 object
中来重构此案例,该对象按需初始化
存在类型
存在类型是一个 已删除的特性,这使得以下代码无效。
def foo: List[Class[T]] forSome { type T } // In Scala 3, Error: Existential types are no longer supported
存在类型是 Scala 2.13 中的一个实验特性,必须通过导入
import scala.language.existentials
或设置-language:existentials
编译器标志来显式启用。
在 Scala 3 中,建议的解决方案是引入一个包含从属类型的封闭类型
请注意,使用通配符参数 _
或 ?
通常更简单,但并非总是可行。例如,您可以用 List[?]
替换 List[T] forSome { type T }
。
专门化
Scala 2 中的 @specialized
注解在 Scala 3 中被忽略。
但是,对专门化的 Function
和 Tuple
有限支持。
可以从 inline
声明中获得类似的好处。