0%

【文章翻譯】Announcing Dart null safety beta

【文章內容使用 Gemini 1.5 Pro 自動翻譯產生】

宣佈 Dart 空安全 Beta 版

此文章交叉發佈於此處和 Flutter 部落格

今天我們宣佈 Dart 和 Flutter 的 Beta 版已提供完善的空安全功能。空安全是我們最新的主要生產力功能,旨在幫助您避免空值錯誤,這是一類通常難以發現的錯誤。如果您正在尋找我們為何對空安全感到興奮的快速摘要,請查看這部新影片:

隨著空安全進入 Beta 版,是時候開始社群遷移 pub.dev 上可用的數千個套件了。我們已經遷移了 Dart 核心程式庫、Flutter 架構,以及超過 40 個 Dart 和 Flutter 套件。有了這些,我們希望看到社群透過遷移他們的套件來擁抱空安全。

Timeline of Dart sound null safety support, from Technical Preview 1 to Stable in early 2021

隨著 Beta 版的推出,我們也開始在發佈空安全功能的穩定版本之前的最後階段。我們希望您能使用此功能,並讓我們知道它的哪些部分可以改進,UI 訊息是否可以更容易理解,或者文件是否可以更清晰。我們**非常期待收到您的回饋**。

選擇加入空安全

在我們討論空安全遷移之前,需要重複的是(如我們的空安全原則中所述),您可以控制何時開始採用空安全。只有當應用程式和套件的最低 Dart SDK 限制 至少是 Dart 2.12 預發佈版時,它們才會以空安全模式執行:

1
2
environment:
sdk: ">=2.12.0-0 <3.0.0"

要體驗這一點,請嘗試建立一個小的空安全 hello 應用程式(例如,使用 dart create),其中包含如下所示的程式碼。然後,您可以嘗試在更改 SDK 限制並執行 dart pub get 之前和之後執行應用程式,並體驗程式行為的變化。(確保使用在 dart --version 中報告 2.12 的 SDK。)

1
2
3
4
5
6
7
8
9
// bin/hello.dart:
...
void main() {
var hello = 'Hello Dart developers';
if (someCondition) {
hello = null;
}
print(hello);
}
1
2
# 更改 SDK 限制之前:
$ dart run
1
null
1
2
# 更改 SDK 限制之後(並執行 dart pub get):
$ dart run
1
2
3
4
bin/hello.dart:6:13: Error: Null can't be assigned to a variable of type 'String' because 'String' is not nullable.

hello = null;
^

遷移至空安全

要將套件(或簡單的應用程式)遷移至空安全,請按照以下五個步驟操作,這些步驟在 dart.dev 的遷移指南中已完整記錄。

步驟 1:檢查您的依賴項是否已準備就緒

我們強烈建議您按順序遷移程式碼,先遷移依賴圖的葉子。例如,如果 C 依賴於 B,而 B 依賴於 A,則先將 A 遷移至空安全,然後是 B,然後是 C。此順序適用於 A、B 和 C 是程式庫、套件還是應用程式。

Illustration of dependency order vs. migration order

為什麼順序很重要?儘管您可以在依賴項遷移之前在遷移程式碼方面取得一些進展,但如果您的依賴項在其遷移期間更改其 API,則您可能會冒險進行第二次遷移。如果您的某些依賴項不是空安全的,請考慮使用 pub.dev 上列出的每個套件的聯絡方式與套件發佈者聯繫。

驗證依賴項是否已準備就緒

要驗證您的應用程式或套件是否已準備好開始遷移,您可以使用空安全模式下的 dart pub outdated。以下範例顯示,如果此應用程式將其依賴項升級到 可解析 欄中列出的 pathprocesspedantic 的預發佈版本,則它已準備好遷移。

Screenshot of `dart pub outdated` output

如果在新的小版本中提供空安全支援,您將在 可升級 欄中看到它們。通常,在新的大版本中會提供空安全支援;在這種情況下,您將在過時輸出的 可解析 下看到列出的版本。要升級到這些版本,請編輯您的 pubspec.yaml 檔案以允許這些主要版本。例如,您可以將 process: ^3.0.13 更改為 process: ^4.0.0-nullsafety

您還可以使用套件頁面上的新 空安全 標籤(例如 collection 1.15)和新的進階搜尋 空安全搜尋選項 在 pub.dev 上找到具有空安全支援的套件。

Screenshot of pub.dev search

步驟 2:使用遷移工具進行遷移

如果您的依賴項已準備就緒,則可以使用遷移工具 dart migrate 繼續遷移您的應用程式或套件。

遷移工具是互動式的,因此您可以查看工具推斷出的可空性屬性。如果您不同意工具的任何結論,您可以加入可空性提示以更改推斷。加入一些遷移提示可以對遷移品質產生巨大影響。

Screenshot of the migration tool UI

我們已經讓少數 Dart 套件作者使用空安全的早期預覽版本測試遷移,他們的回饋令人鼓舞。遷移指南中包含有關如何使用遷移工具的更多提示。

步驟 3:靜態分析您遷移的程式碼

在您的 IDE 或命令列中使用 pub get 更新您的套件。然後使用您的 IDE 或命令列對您的 Dart 程式碼執行靜態分析:

1
2
$ dart pub get
$ dart analyze

或者在您的 Flutter 程式碼上:

1
2
$ flutter pub get
$ flutter analyze

步驟 4:確保測試通過

執行您的測試並確保它們通過。您可能需要更新預期空值的測試,以防您更改了套件程式碼以不再允許空值。

步驟 5:發佈您的空安全套件

當遷移完成且測試通過後,您可以將您的套件作為預發佈版本發佈。以下是最佳實務的簡要摘要:

  • 將您的版本號遞增到下一個主要版本(例如,從 2.3.x 到 3.0.0)。此最佳實務可確保您的套件的使用者在準備好自己使用空安全之前不會升級到它,並且讓您可以自由地重構 API 以最佳地利用空安全。
  • 在 pub.dev 上將您的套件作為預發佈版本進行版本控制和發佈。(例如,使用 3.0.0-nullsafety.0,而不是 3.0.0。)

有關遷移和版本控制的完整詳細資訊,請參閱遷移指南

完善空安全的好處

我們之前關於 Dart 和 Flutter 中空安全的技術預覽的部落格文章透過許多範例討論了空安全的好處。現在,隨著空安全即將完成,我們看到了此好處的一些真實範例。

更安全的程式碼

就在最近,我們在 Flutter master channel 中發現了一個錯誤,其中各種 flutter tool 命令會在某些機器配置上因空值錯誤而崩潰:在空值上呼叫了方法 '>='。根本原因是最近的一個拉取請求,用於加入對偵測 Android Studio 4.1 的支援。該 PR 加入了如下程式碼:

1
2
3
4
5
6
final int major = version?.major;
final int minor = version?.minor;
if (globals.platform.isMacOS) {
/// Android Studio 4.1 版之後的 Plugin 路徑已更改。
if (major >= 4 && minor >= 1) {
...

您能發現錯誤嗎?因為 version 可能為空,majorminor 也可能為空。這個錯誤在這裡單獨看來似乎很容易發現,但在實務中,這樣的程式碼總是會溜走,即使是像 Flutter 儲存庫中使用的嚴格程式碼審查流程也是如此。使用空安全,靜態分析立即捕獲此問題

Screenshot of analysis output in an IDE

那是一個相當簡單的錯誤。在我們在 Google 內部程式碼中早期使用空安全的過程中,我們已經看到更多複雜的錯誤被捕獲,然後透過空安全解決。以下是一些範例:

  • 一個內部團隊發現,他們經常在空安全知道永遠不會為空的程式碼中檢查空值。此問題最常見於使用 protobuf 的程式碼中,其中可選欄位在未設定時返回預設值,而不是空值。這會導致程式碼透過混淆預設值和空值來錯誤地檢查預設條件。
  • Google Pay 團隊在他們的 Flutter 程式碼中發現了錯誤,在嘗試在 Widget 上下文之外存取 Flutter State 物件時,它們會失敗。在空安全之前,這些會返回空值並掩蓋錯誤;使用空安全,完善的分析確定這些屬性永遠不會為空,並拋出分析錯誤。
  • Flutter 團隊發現了一個錯誤,如果將空值傳遞給 Window.render() 中的 scene 參數,Flutter 引擎可能會崩潰。在空安全遷移期間,他們加入了一個提示以將 Scene 標記為不可為空,然後能夠輕鬆地防止如果傳遞空值會觸發的潛在應用程式崩潰。

在編譯期間利用完善的空安全

Dart 空安全的完善性還有另一個令人歡迎的含義:這意味著 Dart 編譯器可以利用可空性資訊。這可能會使您的程式更小、更快。我們還沒有很多真實世界的應用程式完全遷移到完善的空安全(因為我們現在才剛剛開始這些應用程式所依賴的套件的生態系統遷移以實現完善性),但我們從核心架構中看到了非常令人鼓舞的結果。

我們最近對 hello_world 範例進行了測試重新編譯,以測量空安全對應用程式大小的影響。這是一個最小化的範例,只顯示「hello world」。在比較編譯程式碼的總大小時,未壓縮的(安裝在設備上的)程式碼大小縮小了 3.5%,除了使用完善的空安全重新編譯之外沒有做任何事情。儘管這個應用程式只有 10 行程式碼,但這也是可能的,因為所有包含的程式庫的程式碼大小都縮小了;例如 Flutter 架構本身(package:flutter)縮小了 3.9%。

至於程式碼速度,必須強制執行完善的型別系統可能會增加開銷。但是,進行更少的空值檢查也可能會使程式碼更快。我們對基準測試的初步分析顯示,效能與以前的版本相當,並且新的額外型別資訊為我們未來進行新型別的效能改進創造了潛力。我們計畫在未來的部落格文章中詳細介紹我們的效能工作。

在某些情況下,我們已經看到空安全會帶來效能提升,通常是在遷移至空安全時發現了程式碼邏輯中的缺陷。例如,我們在 Flutter 網頁文字佈局快取中發現了一個問題。此快取使用的鍵是可為空的,然後是一些在為空時使用 TextAlign.start 的邏輯。此邏輯導致快取中的缺陷,即使元素仍然具有預設值,它們看起來也像已更改。因此,經常發生快取未命中。加入一個不可為空的 textAlign getter 有助於修復快取缺陷,從而在文字被快取的情況下使文字渲染效能提高 14 倍

立即開始!

包含空安全的 Dart 和 Flutter 的 Beta 版本今天已經準備好了。如果您使用 Flutter 進行開發,您可以使用 flutter channel beta 切換到 Beta,然後使用 flutter upgrade。否則,您可以從 Dart SDK 存檔 中獲取獨立的 Dart SDK。

如果您開發套件,我們鼓勵您閱讀我們的遷移指南並規劃您的遷移。如果您有任何問題或建議,請告知我們

如果您是應用程式開發人員,您可能希望延遲遷移,直到該功能進入我們的穩定頻道。我們計畫快速處理 Beta 版的回饋,修復任何剩餘的問題。很難說明空安全何時會在穩定版本中發佈的具體時間表,但我們認為是明年年初。

感謝您的支援和回饋,我們正在努力使 Dart 成為更強大的語言,使 Flutter 成為更強大的架構!


宣佈 Dart 空安全 Beta 版 最初發佈在 Dart 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。