0%

【文章翻譯】Announcing Dart null safety beta

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

開始將套件遷移到更健全、更安全的狀態

此文章同時發布於 Dart 部落格 上。

今天,我們宣佈 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
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。以下範例顯示,如果此應用程式將其相依性升級到如 可解析 欄位中列出的路徑、進程和 pedantic 的預覽版本,則它已準備好進行遷移。

Screenshot of `dart pub outdated` output

如果空安全支援在次要新版本中可用,您將在 可升級 欄位中看到它們。通常,空安全支援將在主要新版本中可用;在这种情况下,您将看到在 outdated 输出的 可解析 下列出的版本。若要升級到這些版本,請編輯您的 pubspec.yaml 檔案以允許這些主要版本。例如,您可能會將 process: ^3.0.13 更改為 process: ^4.0.0-nullsafety。

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

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 主頻道中的一个錯誤,其中各種 flutter 工具命令在某些機器設定上會因空錯誤而崩潰:方法 ‘>=’ 被調用於 null 上。潜在问题是最近的一个添加了对检测 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 版本之后发生了变化。
if (major >= 4 && minor >= 1) {
...

你能找到错误吗?由于 version 可能会为 null,major 和 minor 也可能会为 null。这个错误在孤立情况下似乎很容易发现,但在实践中,即使是像 Flutter 存储库中使用的严格代码审查流程,也会经常出现类似的代码。使用空安全功能,静态分析 会立即发现这个问题

Screenshot of analysis output in an IDE

这是一个非常简单的错误。在 Google 内部早期使用空安全功能的代码中,我们已经看到更多复杂的错误被发现,然后通过空安全功能解决。以下是几个例子:

  • 一个内部团队发现,他们经常检查代码中的空值,而空安全功能知道这些空值永远不会为 null。这个问题最常出现在使用 protobuf 的代码中,其中可选字段在未设置时返回默认值,而不会返回 null。这导致代码错误地检查默认条件,因为混淆了默认值和 null 值。
  • Google Pay 团队发现他们的 Flutter 代码中的错误,这些错误在尝试在 Widget 上下文之外访问 Flutter State 对象时会导致失败。在空安全功能之前,它们会返回 null 并隐藏错误;使用空安全功能,健全的分析确定这些属性永远不会为空,并抛出一个分析错误。
  • Flutter 团队发现一个错误,如果将 null 传递给 Window.render() 中的 scene 参数,Flutter 引擎可能会崩溃。在空安全功能迁移期间,他们添加了一个提示,以 将 Scene 标记为不可为空,并且能够轻松地防止潜在的应用程序崩溃,如果传递了 null,这些崩溃可能会被触发。

在編譯過程中利用健全的空安全功能

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

我們最近對 hello_world 範例進行了測試重新編譯,以測量空安全功能對應用程式大小的影響。這是一個最簡單的範例,它只會顯示「hello world」。在 比較 編譯後程式碼的總體大小時,未壓縮的(安裝在設備上的)程式碼大小縮小了 3.5%,而沒有做任何其他事情,只是使用健全的空安全功能重新編譯。這有可能實現,儘管這個應用程式只有 10 行程式碼,因為所有包含的函式庫的程式碼大小都縮小了;例如,Flutter 框架本身(套件:flutter)縮小了 3.9%。

至於程式碼速度,強制執行健全的類型系統可能會增加開銷。但是,減少空檢查也可能會使程式碼執行得更快。我們對基准測試的初步分析表明,效能與以前的版本相當,並且新的額外類型資訊為我們在未來進行新的效能改進提供了潛力。我們計劃在未來的部落格文章中更多地介紹我們的效能工作。

在某些情况下,我们已经看到空安全功能带来了性能提升,通常是在迁移到空安全功能时发现了代码逻辑中的缺陷。例如,我们在 Flutter 网页文字布局缓存中发现了一个问题。这个缓存使用了一个可为空的键,然后使用了一些逻辑来在为空时使用 TextAlign.start。这种逻辑导致缓存出现缺陷,即使元素仍然具有默认值,它们看起来也会像改变了一样。因此,经常出现缓存未命中。添加一个不可为空的 textAlign getter 有助于修复缓存缺陷,从而在文字被缓存的情况下,使文字渲染性能 提高了 14 倍

立即開始吧!

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

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

如果您是應用程式開發人員,您可能更希望延遲遷移,直到該功能出现在我們的穩定通道中。我們計劃快速解决 Beta 版本的回饋,修复任何剩余的问题。很难确定空安全功能将在稳定版中发布的确切时间,但我们预计将在明年年初。

感謝您在我們努力使 Dart 變得更加健壯,以及使 Flutter 變得更加强大的過程中提供支持和回饋!


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