Scala 3 遷移指南

類型推論

語言

此頁面中描述的兩個不相容性是類型推論規則中的故意變更。

其他不相容性可能是由類型推論演算法的替換所造成的。新的演算法比舊的演算法更好,但有時它可能會在 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

在某些罕見的情況下,涉及隱式轉換和執行時期強制轉型,甚至可能導致執行時期失敗。

解決方案是明確指定覆寫方法的傳回類型

class Child extends Parent {
-  override def foo = new RichFoo(super.foo)
+  override def foo: RichFoo = new RichFoo(super.foo)
}

反射類型

Scala 2 反射呼叫已捨棄,並由更廣泛的 程式化結構類型 取代。

Scala 3 可透過讓 scala.reflect.Selectable.reflectiveSelectable 可在任何匯入 scala.language.reflectiveCalls 的地方使用,來模仿 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

直接的解決方案是寫下結構類型。

import scala.language.reflectiveCalls

- val foo = new {
+ val foo: { def bar: Unit } = new {
  def bar: Unit = ???
}

foo.bar

此頁面的貢獻者