回答這個問題前應該要先了解為什麼會有 null
,如果寫過網頁前端的讀者應該很常看到以下程式碼(以react舉例)
if(!apiData){
return <></>
}
其實大部分原因都是因為「我們不確定什麼時候有值」。最常見大概就是來自後端的資料,至於為什麼這樣會產生null
,正如前幾篇文章說過非同步要等待一段時間才會回傳結果,但為了執行緒不阻塞所以執行緒會繼續往下執行程式。
所以有些 Component 必須額外做null check ,否則在 runtime 時就會有幾秒值是null
但如果有Component 有取用這些值,就會發生runtime error,又或者是這次api request是失敗的。但在response回來前我們根本不會知道這些事情。
在 Dart SDK 2.12 版後就是會預設開啟 Sound null safety,其中最大的前提是
「如果沒有特別說明所有的type都是non-nullable的」
所以我們現在如果真的有個Type有可能是 null 那我們可以用 Type?
來表示這個變數是nullable的,像是下面例子中的 String? apiData
class Foo {
String? apiData;
Future<void> fecthData() async {
await Future.delayed(Duration(seconds: 0), () {
apiData = 'hello wrold';
});
}
}
// ...
final foo = Foo()
foo.apiData.length // 這行會出錯
所以當我們使用 foo.apiData.length
時,就會靜態檢查期間就有error出現:
而如果我們硬要run 就會直接跳出error
從這個例子我們就可以看到null safety 對我們開發有多大的幫助,因為我們不用實際run就可以知道哪部分的code可能會有null相關的runtime error。
那我們要怎麼操作nullable type的變數呢?
基本上有兩種方式 ?
!
?.
就跟JS的optional chaining一樣:如果存取到null就直接return null而不是直接throw error
print(foo.apiData?.length);
// null
!
則是表示這個變數「現在」一定不是null
我們先宣告一個input type 為 String
的function
String concatString(String input) => input + '---';
// ...
final foo = Foo();
await foo.fecthData();
concatString(foo.apiData);
concatString(foo.apiData!);
print(foo.apiData!.length);
會發現即使我們是在 fetchData()
後再取用 foo.apiData
這裡的type 依然是 String?
,雖然我們能夠確定他一定有值,但這是靜態檢查不出來的。所以我們可以加上!
讓編譯器知道:
「這個值雖然是nullable type,但它現在一定不是null哦」
所以我們就能將 原本是 String?
的變數放進去只接受 String
的function裡,也能夠正確的調用 .length
了。
還記得在很久很久之前看到的 late
嗎
先在一個 class
中先用 final
宣告兩個成員然後其中一個加上 late
:
late final String a;
final String b;
Test(this.b);
void setInitValue() {
a = 'a';
}
如果在constructor沒有放this.b
會看到hint 只有跳出 b
需要 initialize
但late
只是可以讓 null
檢查延遲到運行而不是編譯,所以如果忘記 initialize 在runtime還是會有error跳出來。
final test = Test('');
//test.setInitValue();
print(test.a);
今天的程式碼:
https://github.com/zxc469469/dart-playground/tree/Day12/null-safety
Sound null safety 只是很大一部份提升我們在開發時體驗,但這不代表一定不會有bug,畢竟你可能真的沒有去set資料導致你之後!
其實是標爽的,又或者標 late
的變數忘記 initialize,另外還有一個好處就是會提升程式的編譯效率,因為編譯器可以少做一些null check。
而明天將是Dart篇的最後一篇文章,也就是稍微提一下 Functional programming(FP)的概念。之後就要進入Flutter的世界了~
參考資料:
https://juejin.cn/post/6958965184631144478