遷移至空安全
本文將介紹如何將你的程式碼遷移至 空安全。以下是對你的 package 逐個遷移的基本步驟:
-
等待 你依賴的 package 遷移完成。
-
遷移 你的 package 的程式碼,最好使用互動式的遷移工具。
-
靜態分析 package 的程式碼。
-
測試 你的程式碼,確保可用。
-
如果你已經在 pub.dev 上釋出了你的 package,可以將遷移完成的空安全版本以 預釋出 版本進行 釋出。
如果你想預覽遷移工具的體驗,可以檢視以下影片:
可互動的遷移工具讓你可以簡化遷移至空安全的過程。
1. 等待遷移
我們強烈建議你按順序遷移程式碼,先遷移依賴關係中的處於最末端的依賴。例如,如果 C 依賴了 B,B 依賴了 A,那麼應該按照 A -> B -> C 的順序進行遷移。
雖然你在你的所有依賴遷移完成前就 可以 進行遷移,但在它們遷移完成後,你可能需要再對你的程式碼進行調整。例如,如果你推測一個函式可以接受一個可空的引數,但依賴的 package 遷移後變為了非空,在傳遞可空的引數時便會出現編譯錯誤。
該節會講述如何在空安全模式下,使用 dart pub outdated
檢查並更新你的依賴。如果你的程式碼應用了 版本管理,你可以隨時回滾所有的改動。
切換至 Dart 2.19 版本
切換到 Dart SDK 的 Dart 2.19 穩定版,它包含在 Flutter 3.7 SDK 中。
執行下面程式碼檢視是否使用了 Dart 2.19 版本:
$ dart --version
Dart SDK version: 2.19.6
檢查所有依賴的遷移狀態
透過以下命令檢查你的 package 的遷移狀態:
$ dart pub outdated --mode=null-safety
如果你看到所有依賴都已支援空安全,就意味著你可以開始遷移了。否則請使用 Resolvable 列內列舉的已遷移至空安全的版本。
這是一個簡單的 package 的輸入範例。每個 package 的綠色對勾代表著對應版本已支援空安全:
上面的輸出說明了所有依賴的 package 都有可使用的已支援空安全的預釋出版本。
如果你的 package 的依賴中,有一些 尚未 支援空安全,我們推薦你聯絡對應依賴的作者。你可以在 pub.dev 對應 package 的頁面,找到作者的聯絡資訊。
升級依賴
在遷移你的 package 的程式碼之前,請將它的依賴項升級至空安全版本。
-
執行命令
dart pub upgrade --null-safety
將依賴升級至支援空安全的最新版本。 注意: 該命令會更改你的pubspec.yaml
檔案。 -
執行命令
dart pub get
。
2. 遷移
你的程式碼裡大部分需要更改的程式碼,都是可以輕易推導的。例如,如果一個變數可以為空,它的型別需要 ?
字尾。一個不可以為空的命名引數,需要使用 required
標記,或者給定其一個 預設值。
針對遷移,你有兩個選項可以選擇:
-
使用遷移工具,它可以幫你處理大多數可推導的變更。
使用遷移工具
遷移工具會帶上一個非空安全的 package ,將它轉換至空安全。你可以先在程式碼中新增 提示標記 來引導遷移工具的轉換。
開始轉換前,請做好如下的準備:
-
使用最新的 Dart 2.19 SDK 版本。
-
執行
dart pub outdated --mode=null-safety
以確保所有依賴為最新且空安全。
在包含 pubspec.yaml
的目錄下,執行 dart migrate
命令,啟動遷移工具。
$ dart migrate
如果你的 package 可以進行遷移,工具會輸出類似以下的內容:
View the migration suggestions by visiting:
http://127.0.0.1:60278/Users/you/project/mypkg.console-simple?authToken=Xfz0jvpyeMI%3D
使用 Chrome 瀏覽器存取 URL,你可以看到一個互動式的介面,引導你進行遷移:
你可以在工具中看到其推斷的所有變數和型別註解。例如,在上面的截圖中,工具推斷第一行的 ints
列表元素可能為空,所以應該變為 int?
(先前為 int
)。
理解遷移的結果
若要了解每個變化(或者未變化)的原因,點選 Proposed Edits 視窗中的行數,原因會出現在 Edit Details 視窗中。
舉個例子,假設我們有如下的非空安全的程式碼:
var ints = const <int>[0, null];
var zero = ints[0];
var one = zero + 1;
var zeroOne = <int>[zero, one];
當這些程式碼處在函式外時,預設的遷移改動是向後相容的,但並不理想(在函式內時會稍有不同):
var ints = const <int?>[0, null];
var zero = ints[0];
var one = zero! + 1;
var zeroOne = <int?>[zero, one];
點選 line 3 連結,你可以看到遷移工具新增 !
的原因。而因為你知道 zero
不會為空,所以你可以改進遷移結果。
改進遷移的結果
當分析結果推導了錯誤的可空性時,你可以新增臨時的提示標記來改變建議的編輯:
-
在遷移工具的 Edit Details 窗格中,你可以透過 Add
/*?*/
hint 和 Add/*!*/
hint 按鈕來新增提示標記。按下這些按鈕,相應的標記會立刻新增到程式碼中,並且 無法撤銷。如果你想刪除標記,可以和平常一樣使用程式碼編輯器刪除它。
-
就算遷移工具正在執行,你也可以使用編輯器新增提示標記。由於你的程式碼還未遷移到空安全,所以無法使用空安全的新特性。但是你可以進行與空安全無關的改動,例如重構。
當你完成編輯後,點選 Rerun from sources 進行更改。
下方的表格展示了可以使用的提示標記。
|
|
---|---|
expression /*!*/ |
|
type /*!*/ |
|
/*?*/ |
|
/*late*/ |
|
/*late final*/ |
|
/*required*/ |
|
一個提示也可能產生蝴蝶效應,影響其他的程式碼。在先前的例子中,如果在 zero
被賦值的位置(第二行)新增一個 /*!*/
標記,遷移工具就會推斷 zero
的型別是 int
而非 int?
。這就會影響到直接或間接使用了 zero
的程式碼。
var zero = ints[0]/*!*/;
透過添加了以上的提示,遷移工具將調整建議的更改,如下面的程式碼所示。第三行的 zero
後面不再有 !
,第四行的 zeroOne
也被推斷為 int
列表而不是 int?
。
|
|
---|---|
|
|
只遷移部分檔案
儘管我們希望你能一次性完成遷移工作,但對於大體量的應用或 package 而言並不是簡單的事。如果你想只遷移部分檔案,請將暫時不遷移的檔案前方的綠色勾選框取消勾選。稍後應用遷移更改時,這些檔案會加上 Dart 2.9 版本註釋,其他內容保持不變。
更多有關漸進遷移空安全的內容,請閱讀 非健全的空安全。
請注意,從 Dart 3 開始,只支援完全遷移到空安全的應用和 package。
應用更改
當你覺得遷移工具提示的更改部分可以應用了,點選 Apply migration。遷移工具會刪除所有的提示標記,儲存遷移後的程式碼。同時,遷移工具也會更改 pubspec 的 SDK 限制,將 package 遷移至空安全。
下一步就是對程式碼進行 靜態分析。如果一切正常,下一步就是 測試你的程式碼。最後,如果你已經將 package 釋出至 pub.dev, 釋出空安全的預覽版本。
手動遷移
如果你不想使用遷移工具,你也可以手動進行遷移。
我們推薦你 優先遷移最下層的函式庫 —— 指的是沒有匯入其他 package 的函式庫。接著遷移直接依賴了下層庫的依賴庫。最後再遷移依賴項最多的函式庫。
舉個例子,假設你的 lib/src/util.dart
匯入了其他(空安全)的 package 和核心庫,但它沒有包含任何 import '<本地路徑>'
的參考。那麼你應當優先考慮遷移 util.dart
,然後遷移依賴了 util.dart
的檔案。如果有一些迴圈參考的函式庫(例如 A 參考了 B,B 參考了 C,C 參考了 A),建議同時對它們進行遷移。
手動對 package 進行遷移時,請參考以下步驟:
-
編輯 package 的
pubspec.yaml
檔案,將最低 SDK 版本設定到至少為2.12.0
:environment: sdk: '>=2.12.0 <3.0.0'
-
重新產生 package 的配置檔案:
$ dart pub get
在版本最低是
2.12.0
的 SDK 上執行dart pub get
時,會將每個 package 的預設 SDK 最低版本設定為 2.12,並且預設它們已經遷移至空安全。 -
在你的 IDE 上開啟package 。
你也許會看到很多錯誤,沒關係,讓我們繼續。 -
利用分析器來辨析靜態錯誤,逐個遷移 Dart 檔案。
按需新增?
、!
、required
以及late
來消除靜態錯誤。
想獲得更多手動遷移的幫助,請前往 非健全的空安全。
3. 分析
更新你的 package(在 IDE 或命令列工具中使用 dart pub get
)後在 IDE 或命令列工具中對你的程式碼進行 靜態分析:
$ dart pub get
$ dart analyze # or `flutter analyze`
4. 測試
如果你的程式碼通過了分析,接下來可以開始測試:
$ dart test # or `flutter test`
你可能需要更新使用了空值作為預期使用案例的測試程式碼。
如果你需要對程式碼作出大量的更改,那麼你可能需要重新對程式碼進行遷移。這時請先回滾程式碼更改,再執行遷移工具進行遷移。
5. 釋出
我們希望你完成遷移後儘快將其釋出,可以作為預覽版:
-
釋出 package。如果你不想釋出穩定版本,你可以 釋出為預釋出版本。
更新 package 的版本
Package 的版本
你可以修改版本以表示該版本包含了破壞性的改動:
-
如果你的 package 版本已經大於或等於
1.0.0
,請提升主版本。例如,上一個版本為2.3.2
,那麼新版本應該為3.0.0
。 -
如果你的 package 的版本還未高於
1.0.0
,你可以 提升次版本,也可以 提升至1.0.0
。例如,上一個版本為0.3.2
,那麼新版本可以是0.4.0
或1.0.0
。
檢查你的 pubspec
在你釋出穩定版本的空安全 package 前,我們強烈建議你遵循以下 pubspec 的規則:
-
將 SDK 的最低限制設定為你測試過的最低穩定版本(至少是
2.12.0
)。 -
所有的直接依賴都使用穩定版本。
歡迎使用空安全
If you made it this far, you should have a fully migrated, null-safe Dart package.
If all of the packages you depend on are migrated too, then your program is sound with respect to null-reference errors. You should see output like this when running or compiling your code:
Compiling with sound null safety
如果你走到了這一步,你應該已經完全將你的 Dart package 遷移至空安全了。當你的所有依賴也都完成了遷移,那麼你的程式就是健全的,同時可以正確處理空參考的錯誤。
謹代表 Dart 團隊的所有成員,感謝你 遷移你的程式碼。