目錄

不健全的空值安全

一個 Dart 程式可能包含一些是空值安全的函式庫,以及一些不是的函式庫。這些混合版本程式依賴不健全的空值安全

混合語言版本的能力讓套件維護者可以遷移其程式碼,並且知道即使是舊版使用者也可以獲得新的錯誤修正和其他改進。但是,混合版本程式無法獲得空值安全所能帶來的所有優勢。

本頁說明健全和不健全空值安全之間的差異,旨在協助您決定何時遷移至空值安全。概念性討論之後是關於逐步遷移的說明,然後是關於測試和執行混合版本程式的詳細資訊。

健全和不健全的空值安全

#

Dart 透過靜態和執行階段檢查的組合提供健全的空值安全。每個選擇加入空值安全的 Dart 函式庫都會獲得所有靜態檢查,以及更嚴格的編譯時期錯誤。即使在包含不安全空值函式庫的混合版本程式中也是如此。只要您開始將部分程式碼遷移至空值安全,就會開始獲得這些好處。

但是,混合版本程式無法像完全空值安全的應用程式一樣具有執行階段健全保證。null 可能會從不安全空值的函式庫洩漏到安全空值的程式碼中,因為防止這種情況會破壞未遷移程式碼的現有行為。

為了在提供完全空值安全程式的健全性的同時,維護與舊版函式庫的執行階段相容性,Dart 工具支援兩種模式

  • 混合版本程式以不健全的空值安全執行。null 參考錯誤可能會在執行階段發生,但僅因為 null 或可為空值的類型從某些不安全空值的函式庫逸出並進入安全空值的程式碼。

  • 當程式完全遷移且所有函式庫都是空值安全時,它會以健全的空值安全執行,並具有健全性所能實現的所有保證和編譯器最佳化。

如果可能,健全的空值安全是您想要的。如果程式的主要進入點函式庫已選擇加入空值安全,Dart 工具會自動以健全模式執行您的程式。如果您導入不安全空值的函式庫,這些工具會列印警告,讓您知道它們只能以不健全的空值安全執行。

逐步遷移

#

由於 Dart 支援混合版本程式,您可以一次遷移一個函式庫(通常是一個 Dart 檔案),同時仍然能夠執行您的程式及其測試。

我們建議您先遷移葉函式庫,也就是不從套件匯入其他檔案的函式庫。然後遷移直接相依於葉函式庫的函式庫。最後遷移具有最多套件內相依性的函式庫。

例如,假設您有一個 lib/src/util.dart 檔案,它會匯入其他(空值安全)套件和核心函式庫,但沒有任何 import '<local_path>' 指令。請考慮先遷移 util.dart,然後再遷移僅相依於 util.dart 的檔案。如果任何函式庫具有循環匯入(例如,A 匯入 B,B 匯入 C,而 C 匯入 A),請考慮一起遷移這些函式庫。

使用遷移工具

#

您可以使用遷移工具逐步遷移。若要退出檔案或目錄,請按一下綠色的核取方塊。在下列螢幕截圖中,bin 目錄中的所有檔案都已退出。

Screenshot of file viewer in migration tool

除了 2.9 語言版本註解之外,每個退出的檔案都不會變更。您可以稍後再次執行 dart migrate 以繼續遷移。任何已遷移的檔案都有一個停用的核取方塊:一旦檔案遷移後,您就無法取消遷移。

手動遷移

#

如果您想要手動逐步遷移套件,請遵循下列步驟

  1. 編輯套件的 pubspec.yaml 檔案,將最低 SDK 約束設定為至少 2.12.0

    yaml
    environment:
      sdk: '>=2.12.0 <3.0.0'
  2. 重新產生套件組態檔

    $ dart pub get

    使用較低的 SDK 約束 2.12.0 執行 dart pub get 會將套件中每個函式庫的預設語言版本設定為 2.12,讓它們全部選擇加入空值安全。

  3. 在 IDE 中開啟套件。
    您可能會看到許多分析錯誤。這沒有關係。

  4. 語言版本註解新增至您不想在目前遷移期間考慮的任何 Dart 檔案的頂端

    dart
    // @dart=2.9

    對 2.12 套件中的函式庫使用語言版本 2.9 可以減少來自未遷移程式碼的分析錯誤(紅色波浪線)。但是,不健全的空值安全會減少分析器可以使用的資訊。例如,分析器可能會假設參數類型不可為空值,即使 2.9 檔案可能會傳入空值。

  5. 使用分析器識別靜態錯誤,以遷移每個 Dart 檔案的程式碼。
    視需要新增 ?!requiredlate 來消除靜態錯誤。

測試或執行混合版本程式

#

若要測試或執行混合版本的程式碼,您需要停用健全的空值安全。您可以使用兩種方式執行此動作

  • 使用 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/<packageName>.dart。您也可以退出 test 下的檔案,因為它們也是進入點。範例

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

在您逐步遷移期間,使用這些機制中的任何一種退出測試都很有用,但這樣做表示您沒有啟用完整空值安全的情況下測試您的程式碼。當您完成函式庫的逐步遷移時,請務必將您的測試重新加入空值安全。