跳至主內容

不健全的空安全

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

混合語言版本的能力使包維護者可以自由地遷移其程式碼,同時知道即使是舊版使用者也可以獲得新的錯誤修復和其他改進。然而,混合版本程式無法獲得空安全所帶來的所有優勢。

本頁描述了健全空安全與不健全空安全之間的區別,旨在幫助您決定何時遷移到空安全。概念性討論之後是增量遷移的說明,接著是測試和執行混合版本程式的詳細資訊。

健全與不健全的空安全

#

Dart 透過靜態檢查和執行時檢查的結合提供了健全的空安全。每個選擇啟用空安全的 Dart 庫都會獲得所有靜態檢查,並伴隨著更嚴格的編譯時錯誤。即使在包含非空安全庫的混合版本程式中,這也適用。一旦您開始將部分程式碼遷移到空安全,您就會立即開始獲得這些好處。

然而,混合版本程式無法擁有完全空安全應用所具備的執行時健全性保證。`null` 值可能會從非空安全庫中洩漏到空安全程式碼中,因為阻止這種情況會破壞未遷移程式碼的現有行為。

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

  • 混合版本程式以不健全的空安全模式執行。執行時可能會發生 `null` 引用錯誤,但這僅因為 `null` 或可空型別從某個非空安全庫中“洩漏”並進入了空安全程式碼。

  • 當程式完全遷移並且所有庫都空安全時,它將以健全的空安全模式執行,並享有健全性所帶來的所有保證和編譯器最佳化。

如果可能,您會希望使用健全的空安全。如果您的程式主入口庫已選擇啟用空安全,Dart 工具會自動以健全模式執行您的程式。如果您匯入了非空安全庫,工具會列印警告,告知您它們只能以不健全的空安全模式執行。

增量遷移

#

由於 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` 以繼續遷移。任何已遷移的檔案都會顯示一個停用的複選框:檔案一旦遷移,就無法撤銷遷移。

手動遷移

#

如果您想手動增量遷移一個包,請遵循以下步驟:

  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 檔案可能會傳入一個 `null` 值。

  5. 遷移每個 Dart 檔案的程式碼,使用分析器來識別靜態錯誤。
    根據需要新增 `?`、`!`、`required` 和 `late` 來消除靜態錯誤。

測試或執行混合版本程式

#

要測試或執行混合版本程式碼,您需要停用健全的空安全。您可以透過兩種方式進行操作:

  • 使用 `dart` 或 `flutter` 命令的 `--no-sound-null-safety` 標誌來停用健全的空安全。

    dart --no-sound-null-safety run
    flutter run --no-sound-null-safety
  • 或者,將入口點(包含 `main()` 函式的檔案)中的語言版本設定為 2.9。在 Flutter 應用中,此檔案通常命名為 `lib/main.dart`。在命令列應用中,此檔案通常命名為 `bin/.dart`。您還可以選擇排除 `test` 目錄下的檔案,因為它們也是入口點。例如:

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

使用這些機制之一排除測試對於您增量遷移過程的測試可能很有用,但這樣做意味著您沒有在完全啟用空安全的情況下測試您的程式碼。當您完成庫的增量遷移後,將測試重新啟用空安全非常重要。