本页描述的两个不兼容性是类型推断规则的有意更改。
其他不兼容性可能是由类型推断算法的替换引起的。新算法比旧算法更好,但有时它可能会在 Scala 2.13 成功的情况下失败
始终建议明确编写所有公共值和方法的结果类型。它可以防止库的公共 API 由于不同的推断类型而随着 Scala 版本而更改。
在 Scala 3 迁移之前,可以通过在 Scalafix 中使用 ExplicitResultTypes 规则来完成此操作。
覆盖方法的返回类型
在 Scala 3 中,覆盖方法的返回类型是通过从基方法继承推断出来的,而在 Scala 2.13 中,它是从覆盖方法的左侧推断出来的。
class Parent {
def foo: Foo = new Foo
}
class Child extends Parent {
override def foo = new RichFoo(super.foo)
}
在此示例中,Child#foo
在 Scala 2.13 中返回 RichFoo
,但在 Scala 3 中返回 Foo
。这会导致编译器错误,如下所示。
class Foo
class RichFoo(foo: Foo) extends Foo {
def show: String = ""
}
class Parent {
def foo: Foo = new Foo
}
class Child extends Parent {
override def foo = new RichFoo(super.foo)
}
(new Child).foo.show // Scala 3 error: value show is not a member of Foo
在涉及隐式转换和运行时转换的一些罕见情况下,它甚至可能导致运行时失败。
解决方案是显式指定覆盖方法的返回类型
反射类型
Scala 2 反射调用已被删除,并由更广泛的 程序化结构类型 取代。
Scala 3 可以通过在导入 scala.language.reflectiveCalls
的任何地方提供 scala.reflect.Selectable.reflectiveSelectable
来模仿 Scala 2 反射调用。但是,Scala 3 编译器默认情况下不会推断结构类型,因此无法编译
import scala.language.reflectiveCalls
val foo = new {
def bar: Unit = ???
}
foo.bar // Error: value bar is not a member of Object
简单的解决方案是写下结构类型。