0%

【文章翻譯】How Dart’s null safety helped me augment my projects

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

我將一個正在執行的應用程式和一個已發佈的套件遷移到空安全,體驗太棒了!

關於作者: Waleed Arshad 是一位核心行動技術專家,也是一位充滿熱情的跨平台開發者,更是巴基斯坦第一位獲得 Flutter Google 開發專家認證的人。從卡拉奇 FAST 畢業後,他在業界工作了五年多,目前在 Tendermint 的 Flutter 開發者體驗團隊工作。他同時也領導著巴基斯坦的 Flutter 社群。

隨著 Flutter 2 的推出,空安全功能已在 Flutter 的穩定頻道上可用。這篇文章將討論我將應用程式和套件遷移到空安全以及從頭開始建立空安全應用程式的個人經驗。簡而言之,結果令人驚豔!

如果您不熟悉 Flutter 的空安全功能,請查看空安全公告。如果您想完全理解空安全,請查看Dart 空安全文件

本文描述了我使用空安全的兩種經驗:

  • 遷移應用程式和套件
  • 在空安全環境中編寫新程式碼

遷移應用程式和套件

當我第一次將 Flutter 升級到 2.0 版(支援空安全的版本)並將 Dart SDK 版本更新到 2.12 時,我在 Flutter 應用程式的 pubspec.yaml 檔案中看到了很多錯誤。我最初想嘗試手動遷移到空安全(即不使用遷移工具進行遷移),所以我開始手動解決空安全錯誤——在我的程式碼中到處添加問號和驚嘆號。我故意這樣做,只是為了理解 Flutter 團隊在 空安全遷移工具 上所做的所有努力,以自動化更改和更新程式碼的流程!經過一些實驗後,我還原了所有手動進行的更改,並使用了該工具的魔力來完成應用程式的遷移。

該應用程式是一個實驗性的 COVID-19 統計應用程式,其程式碼是完全開源的。您可以在 GitHub 上找到它。

看到遷移工具在我的專案中所做的所有程式碼更改真的很酷——例如在可空值中添加問號,以及在遷移工具檢測到值永遠不會為空時添加驚嘆號。

以下是一個遷移工具自動添加問號和驚嘆號的例子。_homeCountry 是一個名為 HomeCountry(也是可空值)的類別的可空值屬性。因此,為了保護對 _homeCountry 其中一個屬性的存取,該工具添加了問號運算子。

遷移之後,程式碼中的一些問題變得明顯,這是最好的部分

其中一個問題是,一些可空值的字串作為列表傳遞給 shared_preferences Plugin 的內部函數。因為這些值是可空值的,所以工具將整個列表類型設為 <String?>[],這開始產生錯誤,因為該函數接受的類型是 <String>[]

這個問題的一個簡單解決方案是移除問號,並使列表類型與函數參數的類型匹配。當我這樣做時,分析器開始提示可空值類型 (String?) 無法賦值給不可空值類型 (String)。

為了解決這個問題,我將 HomeCountry 類別的每個屬性都設為不可空值,並在建構函數中添加了 required 關鍵字。這意味著現在在初始化 HomeCountry 時必須傳遞參數。我不必更改 setHomeCountry 函數,因為傳遞給列表的變數現在是不可空值的。

這個更改防止了我在程式碼中錯誤地將空值傳送給 shared preferences,這是空安全功能提供的非常有價值的輸入!

空安全發現的另一件事是一個可能導致執行時崩潰的錯誤。請參見以下程式碼片段:

A screenshot of code for setState() that assumes (but doesn’t check) that list isn’t null.

因為 list 是一個可空值的變數,讀取其基於索引的元素可能會導致崩潰。遷移到空安全後,我無法編譯應用程式,因為在讀取此列表中的值之前沒有進行空檢查。

最終,我添加了一個空檢查,以使程式碼能夠編譯,並防止應用程式在此程式碼處崩潰。令人驚訝的是,遷移是如何幫助我發現一個實際的錯誤!

In this code sample, the code for setState is protected by a null check: `if (list != null)`
setState 的程式碼現在有效,因為 list 不為空。

我也碰巧遷移了一個非常小的套件,您可以在 pub.dev 上找到它,名為 progress_indicators。我驚訝地發現,當遷移工具得出結論認為這些變數在使用前已初始化時,它添加了 late 關鍵字而不是問號。

A screenshot of source code for a class that has `late` fields.

在空安全環境中編寫新程式碼

現在 Flutter 具有空安全功能,建立新的應用程式可以提供更好的開發體驗。在空安全環境中編寫新程式碼還可以更好地理解程式碼流程,並且能夠編寫防崩潰程式碼。您現在無法使用如下的類別建立可編譯的程式碼:

1
2
3
4
5
class MyClass {
String a;

MyClass({this.a});
}

這段程式碼會導致編譯時錯誤,提示您將 a 標記為可空值,在建構函數中添加 required 關鍵字,或添加初始化器。程式碼確保 a 永不為空。因此,根據您的使用案例,您可以這樣做:

1
2
3
4
5
class MyClass {
String? a;

MyClass({this.a});
}

或者您可以這樣做:

1
2
3
4
5
class MyClass {
String a;

MyClass({required this.a});
}

請注意,從 Flutter 2(和 Dart 2.12)開始,您不再需要在 required 關鍵字前添加 @ 符號。

或者您可以將 a 保持為可選的,但添加一個初始化器,如果沒有傳遞值,則賦予它一個預設值:

1
2
3
4
5
class MyClass {
String a;

MyClass({this.a = ''});
}

此外,您現在可以建立自己建立的類別的可空值變數:

1
2
3
4
5
6
7
8
class MyClass {
String? a;

MyClass({this.a});
}

// 在主程式碼中的某處
MyClass? myClass;

因為 myClass 具有可空值類型,如果您編寫如下程式碼,編譯器將會發出錯誤:

1
print(myClass.a);

錯誤如下:

屬性 ‘a’ 無法無條件存取,因為接收器可以為 ‘null’。

您可以透過添加問號來修復該錯誤:

1
print(hello?.a);

Dart 的空安全功能確保您編寫更安全、更不易出錯的程式碼。在編譯時發現與空變數相關的錯誤是對開發體驗的寶貴補充。前面的範例顯示了編譯器如何在檢測到可能導致應用程式在執行時崩潰的空指標異常時阻止您編譯程式碼。這顯然意味著編譯器會盡可能編寫空安全的程式碼(除非您使用 ! 運算子強制展開所有內容)。

總之,Dart 的健全空安全功能是一個可靠的起點,可以用於構建更安全、更快、更可靠的應用程式!整體的編碼體驗現在更加規範和更有條理。我建議您將舊的 Dart 應用程式遷移到空安全,以了解它的工作原理。也許您會幸運地在舊程式碼中發現並修復一些錯誤!

編碼愉快!:)


Dart 的空安全功能如何幫助我增強我的專案 最初發佈在 Medium 的 Dart 上,人們在那裡透過突出顯示和回應這個故事來繼續討論。