目錄

非健全的空安全

A Dart program may contain some libraries that are null safe and some that aren’t. These mixed-version programs rely on unsound null safety.

一個 Dart 程式可以同時包含已經是 空安全 和未遷移至空安全的函式庫。這些 混合模式的程式 會執行在 非健全的空安全 下。

混合模式版本 的空安全,讓軟體套件的維護者可以遷移至空安全的同時,未遷移至空安全的使用者也可以享受新的問題修復和其他改進。然而,混合模式的程式無法擁有空安全帶來的所有優勢。

本文將描述健全和非健全的空安全之間的區別,讓你可以為何時進行空安全遷移下定論。

健全和非健全的空安全

Dart 透過一系列的靜態和執行時期檢查來提供健全的空安全。每一個使用了空安全的 Dart 庫都會擁有所有的 靜態 檢查和更嚴格的編譯期的錯誤提醒。對於包含了空安全庫的混合模式程式也是如此。程式碼一旦開始遷移,已遷移的部分就能立刻享有到它帶來的好處。

然而,混合模式的程式無法獲得與空安全的程式的 執行時 健全性一致的保證。 null 很可能從非空安全的函式庫汙染到空安全的程式碼,因為一旦它被阻止,就會對現有的程式碼行為造成破壞。

為了在保持與傳統庫執行時的相容性的同時,能為健全的空安全程式提供健全性, Dart 工具提供了以下兩種模式的支援:

  • 非健全的空安全 執行的混合模式的程式。在執行時有可能出現 null 參考錯誤,但這只是因為一些 null 值和可空型別在非空安全的函式庫中汙染了空安全的程式碼。

  • 當程式完全遷移至空安全,且它所依賴的函式庫 全部 都遷移完成後,它就在以 健全的空安全 執行,擁有所有由健全性帶來的保證和編譯最佳化。

健全的空安全唾手可得。當你的程式入口的函式庫已經遷移至空安全,Dart 會自動以健全的空安全執行你的程式碼。如果你匯入了非空安全的函式庫,會有一條提示告訴你,你的程式只能以非健全的空安全執行。

逐步遷移

因為 Dart 支援混合模式的空安全,所以你可以一個個遷移你的函式庫(通常是一個檔案),同時能正常執行程式和測試。

我們推薦你 優先遷移最下層的函式庫——指的是沒有匯入其他套件的庫。接著遷移直接依賴了下層庫的依賴庫。最後再遷移依賴項最多的函式庫。

舉個例子,假設你的 lib/src/util.dart 匯入了其他(空安全)的軟體包和核心庫,但它沒有包含任何 import '<本地路徑>' 的參考。那麼你應當優先考慮遷移 util.dart,然後遷移依賴了 util.dart 的檔案。如果有一些迴圈參考的函式庫(例如 A 參考了 B,B 參考了 C,C 參考了 A),建議同時對它們進行遷移。

使用遷移工具

你可以使用 遷移工具 進行漸進遷移。如果你需要排除部分檔案或資料夾,勾選綠色的勾選框。下方的截圖中,bin 資料夾的所有檔案都已被排除。

Screenshot of file viewer in migration tool

每個不遷移的檔案都會加上 2.9 語言版本的註釋。你可以之後再次執行 dart migrate 繼續遷移。已遷移的檔案將顯示為禁用的勾選框,它們無法撤銷遷移更改。

手動進行遷移

手動對 package 進行遷移時,請參考以下步驟:

  1. 編輯 package 的 pubspec.yaml 檔案,將最低 SDK 版本設定到 2.12.0

    environment:
      sdk: '>=2.12.0 <3.0.0'
    
  2. 重新產生 Package 的配置檔案

    $ dart pub get
    

    在版本低於 2.12.0 的 SDK 上執行 dart pub get 時,會將每個 package 的預設 SDK 版本設定為 2.12,並且預設它們已經遷移至空安全。

  3. 在你的 IDE 上開啟 package。
    你也許會看到很多錯誤,沒關係,讓我們繼續。

  4. 在所有你不考慮進行遷移的 Dart 檔案頂部加上 語言版本註釋

    // @dart=2.9
    

    在 2.12 的 package 中為庫指定 2.9 的語言版本可以減少一些未遷移的分析錯誤。然而,非健全的空安全減少了分析器中可用的資訊。例如,就算 2.9 版本的檔案中一個引數可能會傳入空值,分析器也可能會假定引數型別不為空,

  5. 利用分析器來辨析靜態錯誤,逐個遷移 Dart 檔案。
    按需新增 ?!required 以及 late 來消除靜態錯誤。

測試或執行混合版本的程式

想要測試或執行混合版本的程式碼,你需要禁用健全的空安全。有兩種方式可以進行操作:

  • dartflutter 命令裡,加入 --no-sound-null-safety 標記禁用。例如:

    $ dart --no-sound-null-safety run
    $ flutter run --no-sound-null-safety
    
  • 或者,設定包含 main() 函式的檔案程式入口的語言版本為 2.9。在 Flutter 應用中,一般是 lib/main.dart。在命令列應用中,一般是 bin/<package 名稱>.dart。同時你也可以設定 test 下的檔案,因為它們也包含程式入口。例如:

    // @dart=2.9
    import 'src/my_app.dart';
    
    void main() {
      //...
    }
    

以上兩種方式的規避,對於 正在 增量遷移的過程非常有用,但這樣做意味著你並未在完全啟用空安全的情況下測試你的程式碼。當你完成增量遷移後,也請記得將測試程式碼 重新 遷移至空安全。