本教學課程是為 sbt 編寫的。然而,只要它支援 Scala 3,此方法對任何其他建置工具而言都非常類似。
在跳轉到 Scala 3 之前,請確認您使用的是最新的 Scala 2.13.x 和 sbt 1.5.x 版本。
現在讓我們逐步了解將整個專案移植到 Scala 3 所需的步驟。
1. 檢查專案先決條件
確認您的專案已準備好進行移植
- 它不得依賴尚未移植到 Scala 3 的巨集函式庫。
- 它不得使用在 Scala 3 中沒有等效項的編譯器外掛程式。
- 它不得依賴
scala-reflect
。
這些先決條件在 前一頁 中有更詳細的說明。
2. 選擇模組
由於 Scala 2.13 和 Scala 3 之間的互通性,您可以從任何模組開始。但是,從依賴項最少的模組開始可能會比較簡單。
如果您在內部使用巨集定義或巨集註解,則必須先移植它們。
3. 設定跨建置
程式碼庫遷移的兩個主要挑戰為
- 讓程式碼編譯
- 確保執行時期行為不變
我們建議採用交叉建置策略,也就是使用 Scala 3 和 Scala 2.13 編譯程式碼。背後的邏輯是,在每次修正後都能使用 Scala 2.13 執行測試,進而確保執行時期行為不變。這對於避免在修正不相容性時可能發生的錯誤至關重要。
在 sbt 中設定交叉建置非常簡短,如下所示
scalaVersion := "3.3.1"
crossScalaVersions ++= Seq("2.13.11", "3.3.1")
此設定表示
- 預設版本為
3.3.1
。 - 執行
++2.13.11
指令可載入 2.13.11。 - 執行
++3.3.1
指令可載入 3.3.1。
請注意,reload
指令將永遠載入預設版本,在此為 3.3.1。
4. 準備相依性
在此階段,如果您執行 compile
,sbt 很可能會抱怨找不到某些相依性。這是因為相依性的宣告版本未針對 Scala 3 發布。
您需要將相依性升級到較新版本,或告訴 sbt 使用該函式庫的 Scala 2.13 版本。
當您變更函式庫相依性時,請務必在專案的所有模組中套用相同的變更。
檢查是否有可用的函式庫 Scala 3 版本。為此,您可以在 Scaladex 中使用版本矩陣。前往函式庫的專案頁面,按一下版本矩陣按鈕,篩選 Scala 3 和 Scala 2.13。
1. 有函式庫的 Scala 3 版本
我們強烈建議使用其中一個可用版本。請確保您選擇的版本不會帶來任何重大變更。
2. 沒有函式庫的 Scala 3 版本
您可以使用函式庫的 Scala 2.13 版本。語法如下
("com.lihaoyi" %% "os-lib" % "0.7.7").cross(CrossVersion.for3Use2_13)
或對於 Scala.js 相依性
("com.lihaoyi" %%% "os-lib" % "0.7.7").cross(CrossVersion.for3Use2_13)
修正所有未解析的相依性後,您可以檢查測試是否仍在 Scala 2.13 中通過
sbt:example> ++2.13.11
[info] Setting Scala version to 2.13.11 on 1 project.
...
sbt:example> example / test
...
[success]
5. 設定 Scala 3 編譯器
Scala 3 編譯器選項與 Scala 2.13 的選項不同:有些已重新命名,有些尚未支援。您可以參閱 編譯器選項查詢 頁面,以調整 scalacOptions
清單至 Scala 3。
您應該提出一個常見選項清單、一個 Scala 2.13 特定選項清單和一個 Scala 3 特定選項清單。
典型的設定如下所示
scalacOptions ++= {
Seq(
"-encoding",
"UTF-8",
"-feature",
"-language:implicitConversions",
// disabled during the migration
// "-Xfatal-warnings"
) ++
(CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) => Seq(
"-unchecked",
"-source:3.0-migration"
)
case _ => Seq(
"-deprecation",
"-Xfatal-warnings",
"-Wunused:imports,privates,locals",
"-Wvalue-discard"
)
})
}
加入 -source:3.0-migration
選項,以開啟 Scala 3 遷移模式。
您還應該停用 -Xfatal-warnings
,以充分利用遷移模式和自動重寫。
6. 解決不相容性
現在是嘗試使用 Scala 3 編譯的時候了
sbt:example> ++3.3.1
[info] Setting Scala version to 3.3.1 on 1 project.
...
sbt:example> example / compile
...
sbt:example> example / Test / compile
example / compile
編譯範例專案的main
來源。它與example / Compile / compile
完全相同。
example / Test / compile
編譯test
來源。
編譯器產生兩個不同層級的診斷
- 遷移警告:這些警告可以用
-rewrite
選項讓編譯器自動修復。 - 錯誤:一段程式碼無法再編譯。
你可以忽略遷移警告,因為編譯器會自動修復它們。但是不相容性錯誤必須手動處理。
許多已知的不相容性列在 不相容性表格 中。你可以在這裡找到錯誤的描述和一些建議的解決方案。
如果可能,你應該嘗試找到一個最能保留程式碼二進位相容性的修復程式。如果你的專案是一個已發布的函式庫,這一點尤其重要。
巨集不相容性無法輕易解決。必須從頭開始重寫大量程式碼。請參閱 巨集程式設計。
修復不相容性後,你可以透過在 Scala 2.13 中執行測試來驗證解決方案。
sbt:example> ++2.13.11
[info] Setting Scala version to 2.13.11 on 1 project.
...
sbt:example> example / test
...
[success]
考慮定期提交你的變更。
修復所有錯誤後,你應該能夠在 Scala 3 中成功編譯。只有遷移警告仍然存在。你可以透過使用 -source:3.0-migration -rewrite
選項編譯來自動修復它們。
sbt:example> ++3.3.1
sbt:example> set example / scalacOptions += "-rewrite"
sbt:example> example / compile
...
[info] [patched file /example/src/main/scala/app/Main.scala]
[warn] two warnings found
[success]
現在你應該移除 -source:3.0-migration
選項,你也可以再次新增 -Xfatal-warnings
選項。不要忘記重新載入。
7. 驗證遷移
在罕見的情況下,不同的隱含值可能會被解析,並改變程式的執行期行為。良好的測試是防止此類錯誤不被注意到的唯一保證。
確保測試在 Scala 2.13 和 Scala 3 中都能通過。
sbt:example> ++2.13.11
sbt:example> example / test
...
[success]
sbt:example> ++3.3.1
sbt:example> example / test
...
[success]
如果您有持續整合管道,現在是為 Scala 3 設定它的時候了。
8. 完成遷移
恭喜!您已成功將模組移植到 Scala 3。可以對每個模組重複相同的程序,直到專案完全遷移到 Scala 3。
您可以保留或刪除 Scala 2.13 交叉建置設定,具體取決於您是否要交叉發佈您的程式。
到此,我們完成 sbt 專案遷移的說明。