遷移到 null safety
本頁介紹如何以及何時將程式碼遷移到 null safety。以下是遷移你擁有的每個包的基本步驟
- 等待你依賴的包完成遷移。
- 遷移你的包程式碼,最好使用互動式遷移工具。
- 靜態分析你的包程式碼。
- 測試以確保你的更改有效。
- 如果包已在 pub.dev 上,則以預釋出 (prerelease) 版本釋出支援 null safety 的版本。
要非正式地瞭解使用遷移工具的體驗,請觀看此影片
1. 等待遷移
#我們強烈建議按順序遷移程式碼,首先遷移依賴關係圖的葉子節點。例如,如果包 C 依賴於包 B,而包 B 依賴於包 A,那麼應首先將 A 遷移到 null safety,然後是 B,最後是 C。

儘管你可以在依賴項支援 null safety 之前進行遷移,但當你的依賴項遷移時,你可能需要更改程式碼。例如,如果你預測函式將接受一個可空引數,但包將其遷移為不可空,那麼傳遞一個可空引數就會成為編譯錯誤。
本節介紹如何藉助 null safety 模式下的 dart pub outdated 命令檢查和更新包的依賴項。說明假定你的程式碼處於版本控制之下,以便你可以輕鬆撤銷任何更改。
切換到 Dart 2.19.6 版本
#切換到 Dart SDK 的 2.19.6 版本。此版本包含在 Flutter 3.7.12 SDK 中。
檢查你是否安裝了 Dart 2.19.6
dart --version
Dart SDK version: 2.19.6檢查依賴狀態
#使用以下命令獲取包依賴項的遷移狀態
dart pub outdated --mode=null-safety如果輸出顯示所有包都支援 null safety,那麼你就可以開始遷移了。否則,請使用Resolvable列查詢支援 null safety 的版本(如果存在)。
以下是簡單包的輸出示例。每個包的綠色勾選版本都支援 null safety

輸出顯示,該包的所有依賴項都有可解析的、支援 null safety 的預釋出版本。
如果你的包的任何依賴項尚未支援 null safety,我們鼓勵你聯絡包所有者。你可以在 pub.dev 上的包頁面上找到聯絡方式。
更新依賴項
#在遷移你的包程式碼之前,將其依賴項更新到支援 null safety 的版本
執行
dart pub upgrade --null-safety將依賴項升級到支援 null safety 的最新版本。注意:此命令會更改你的pubspec.yaml檔案。執行
dart pub get。
2. 遷移
#你的程式碼實現 null safety 所需的大多數更改都很容易預測。例如,如果變數可以為 null,其型別需要新增 ? 字尾。如果命名引數不應可空,請將其標記為 required 或為其指定預設值。
你有兩種遷移選項
使用遷移工具
#遷移工具接收一個不支援 null safety 的 Dart 程式碼包,並將其轉換為支援 null safety 的程式碼。你可以透過在 Dart 程式碼中新增提示標記來指導工具的轉換。
在啟動工具之前,確保你已準備就緒
- 使用 Dart SDK 的 2.19.6 版本。
- 使用
dart pub outdated --mode=null-safety確保所有依賴項都支援 null safety 並已更新到最新版本。
透過在包含包的 pubspec.yaml 檔案的目錄中執行 dart migrate 命令來啟動遷移工具
dart migrate如果你的包已準備好遷移,工具會生成如下所示的一行
View the migration suggestions by visiting:
http://127.0.0.1:60278/Users/you/project/mypkg.console-simple?authToken=Xfz0jvpyeMI%3D在 Chrome 瀏覽器中訪問該 URL,檢視互動式 UI,你可以在其中指導遷移過程

對於每個變數和型別註解,你可以看到工具推斷的可空性。例如,在上面的螢幕截圖中,工具推斷第 1 行的 ints 列表(以前是 int 列表)是可空的,因此應該是一個 int? 列表。
理解遷移結果
#要檢視每個更改(或非更改)的原因,請在Proposed Edits面板中單擊其行號。原因會顯示在Edit Details面板中。
例如,考慮以下程式碼,這是在 null safety 之前編寫的
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];透過單擊第 3 行連結,你可以看到遷移工具新增 ! 的原因。因為你知道 zero 不可能為 null,所以你可以改進遷移結果。
改進遷移結果
#當分析推斷出錯誤的可空性時,你可以透過插入臨時提示標記來覆蓋其建議的更改
在遷移工具的Edit Details面板中,你可以使用Add
/*?*/hint和Add/*!*/hint按鈕插入提示標記。這些按鈕會立即將註釋新增到你的檔案中,並且無法撤消。如果你不想要工具插入的提示,可以使用常用的程式碼編輯器將其刪除。
你可以使用編輯器新增提示標記,即使工具仍在執行。由於你的程式碼尚未選擇加入 null safety,因此無法使用新的 null safety 特性。但是,你可以進行不依賴於 null safety 特性的更改,例如重構。
完成程式碼編輯後,單擊Rerun from sources以載入你的更改。
下表顯示了你可以用來更改遷移工具建議的編輯的提示標記。
| 提示標記 | 對遷移工具的影響 |
|---|---|
表示式 /!/ | 在遷移後的程式碼中新增 !,將表示式強制轉換為其底層不可空型別。 |
型別 /!/ | 將型別標記為不可空。 |
/*?*/ | 將前面的型別標記為可空。 |
/*late*/ | 將變數宣告標記為 late,表示它具有延遲初始化。 |
/*late final*/ | 將變數宣告標記為 late final,表示它具有延遲的、一次性初始化。 |
/*required*/ | 將引數標記為 required。 |
一個提示可能會在程式碼的其他地方產生連鎖反應。在前面的示例中,手動在為 zero 賦值的位置(第 2 行)新增 /*!*/ 標記,會使遷移工具將 zero 的型別推斷為 int,而不是 int?。這種型別更改可能會影響直接或間接使用 zero 的程式碼。
var zero = ints[0]/*!*/;有了上述提示,遷移工具會改變其建議的編輯,如下面的程式碼片段所示。第 3 行 zero 後面不再有 !,第 4 行 zeroOne 被推斷為 int 列表,而不是 int? 列表。
| 首次遷移 | 帶有提示的遷移 |
|---|---|
dart | dart |
退出檔案
#雖然我們建議一次性遷移所有程式碼,但有時這並不實際,尤其是在大型應用或包中。要退出一個檔案或目錄,請單擊其綠色的複選框。稍後,當你應用更改時,每個退出檔案除了 2.9 版本註釋外,將保持不變。
有關增量遷移的更多資訊,請參閱 不健全的 null safety。
請注意,只有完全遷移的應用和包才與 Dart 3 相容。
應用更改
#當你對遷移工具建議的所有更改都滿意時,點選Apply migration。遷移工具會刪除提示標記並儲存遷移後的程式碼。工具還會更新 pubspec 檔案中的最低 SDK 約束,這會將包選擇加入 null safety。
下一步是靜態分析你的程式碼。如果程式碼有效,然後測試你的程式碼。然後,如果你已在 pub.dev 上釋出了程式碼,則釋出一個支援 null safety 的預釋出版本。
手動遷移
#如果你不想使用遷移工具,可以手動遷移。
我們建議你首先遷移葉子庫——不匯入包中其他檔案的庫。然後遷移直接依賴於葉子庫的庫。最後遷移具有最多包內依賴項的庫。
例如,假設你有一個 lib/src/util.dart 檔案,它匯入了其他(支援 null safety 的)包和核心庫,但沒有任何 import '<local_path>' 指令。考慮首先遷移 util.dart,然後遷移僅依賴於 util.dart 的簡單檔案。如果任何庫有迴圈匯入(例如,A 匯入 B,B 匯入 C,而 C 匯入 A),考慮將這些庫一起遷移。
要手動遷移包,請按照以下步驟操作
編輯包的
pubspec.yaml檔案,將最低 SDK 約束設定為至少2.12.0yamlenvironment: sdk: '>=2.12.0 <3.0.0'重新生成包配置檔案
dart pub get執行
dart pub get並將最低 SDK 約束設定為至少2.12.0會將包中每個庫的預設語言版本設定為最低 2.12,從而使它們全部選擇加入 null safety。在你的 IDE 中開啟包。
你可能會看到許多分析錯誤。沒關係。使用分析器識別靜態錯誤,遷移每個 Dart 檔案的程式碼。
透過根據需要新增?、!、required和late來消除靜態錯誤。
有關手動遷移程式碼的更多幫助,請參閱 不健全的 null safety。
3. 分析
#更新你的包(在 IDE 或命令列中使用 dart pub get)。然後使用你的 IDE 或命令列對你的程式碼執行靜態分析
dart pub get
dart analyze # or `flutter analyze`4. 測試
#如果你的程式碼通過了分析,則執行測試
dart test # or `flutter test`你可能需要更新期望 null 值的測試。
如果你需要對程式碼進行較大更改,可能需要重新遷移。如果是這樣,請在使用遷移工具之前恢復你的程式碼更改。
5. 釋出
#我們鼓勵你在遷移完成後儘快釋出包——可能作為預釋出版本
- 設定包版本以指示重大變更。
- 更新 SDK 約束和包依賴項。
- 釋出包。如果你不認為此版本是穩定版本,則將包釋出為預釋出版本。
- 更新示例和文件
更新包版本
#更新包版本以指示重大變更
如果你的包版本已達到
1.0.0或更高,則增加主版本號。例如,如果先前版本是2.3.2,新版本則是3.0.0。如果你的包尚未達到
1.0.0,則可以增加次版本號或者將版本更新為1.0.0。例如,如果先前版本是0.3.2,新版本可以是0.4.0或1.0.0。
檢查你的 pubspec 檔案
#在釋出包的穩定 null safety 版本之前,我們強烈建議遵循這些 pubspec 規則
- 將 Dart 的最低 SDK 約束設定為你已測試過的最低穩定版本(至少
2.12.0)。 - 使用所有直接依賴項的穩定版本。
更新示例和文件
#如果你尚未這樣做,請更新包的所有示例和樣本,使其使用已遷移版本的包並選擇加入 null safety。
如果你為你的包釋出了任何單獨的文件或教程,也請確保它們已更新到支援 null safety 的版本。
null safety 歡迎你
#如果你已經完成了這些步驟,你應該擁有一個完全遷移、支援 null safety 的 Dart 包。
如果你依賴的所有包也已遷移,那麼你的程式在 null 引用錯誤方面是健全的。在執行或編譯程式碼時,你應該會看到類似如下的輸出
Compiling with sound null safetyDart 團隊全體成員衷心感謝你遷移你的程式碼。