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 +

此頁面的貢獻者