Null Safety in Dart --- Introduction (Dart空安全介紹)
歷史
2020年11月空安全進(jìn)入Beta測試階段, 自2.12及Flutter2.0之后開始全面支持Sound null safety
。
介紹
一般來說畦戒,變量儲存了某些值。例如整數(shù)可以是0, 42, -2暖释;一個String可以是 hello world熊经,或者其他什么的內(nèi)容。
// In null-safe Dart, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo();
但是對大部分包括Dart在內(nèi)的編程語言而言斥黑,還有一種空值的概念弟胀,也就是沒有值埃跷。
例如,我喜歡的顏色這個變量邮利,可以是空值,這是合理的垃帅。有些人就是沒有喜歡的顏色延届。
setBackground(my.favoriteColor);
這就產(chǎn)生了一個問題,如果變量既可以是一種類型贸诚。例如整數(shù)或者顏色方庭,又可以是空厕吉,那么你每次使用的時候,都要想一想械念,
這個顏色變量到底存儲了真的顏色值头朱,還是空的顏色值?這一串整數(shù)數(shù)列里的某一個值龄减,到底是整數(shù)项钮,還是空值? ?? 呀噠
事實(shí)證明希停,程序員開發(fā)時不會一天到晚想著這個問題烁巫,常常制造出跟空值有關(guān)的錯誤。NullPointException可不是好東西宠能。 你的應(yīng)用會因此而奔潰亚隙,用戶可不喜歡這樣。
在默認(rèn)設(shè)定中违崇,Dart假設(shè)你的變量都不是空值阿弃。例如,年齡變量不可為空羞延,你不能將它設(shè)為空值渣淳。這有點(diǎn)像雙重否定的概念(Filip Hracek說的)。
my.age = null; // 我靠這是什么, 你的年齡竟然是空肴楷。 ???何者じゃ水由?
換個說法,年齡變量一定是某個數(shù)值赛蔫,不可以是空值砂客。這是默認(rèn)設(shè)定,所有類型的默認(rèn)都是不可為空呵恢。
不過你還是可以使用空值鞠值,但是你要明確的說明。 如果要容許favoriteColor使用空值渗钉,就要加上問好彤恶。這個變量就可以為空。它既可以是顏色值鳄橘,也可以是空值声离。因?yàn)槲覀円呀?jīng)明確標(biāo)識了。
setBackground(my?.favoriteColor);
現(xiàn)在Dart可以幫助我們避免剛才提到的問題瘫怜,如果你使用favoriteColor為color术徊,忘記它可能是空值,Dart就會提醒你鲸湃,這樣你的代碼就更安全了赠涮。
另外子寓,Dart的空安全頁很靠譜。(Filip Hracek說的)笋除。
如果Dart判斷某個變量不可為空斜友,那個變量就從頭到尾就都不可為空。IDE中已經(jīng)會通過上下文做出判斷檢測垃它,不僅僅檢測一行代碼哦鲜屏。正所謂編譯時報(bào)錯,而非運(yùn)行時報(bào)錯了嗤瞎。
許多其他的程序語言并沒有靠譜的空安全機(jī)制墙歪。經(jīng)常要在運(yùn)行期間進(jìn)行檢查。
NullSafety | Sound NullSafety | |
---|---|---|
C# | X | |
Dart | X | X |
Java | X | |
Kotlin | X | |
Swift | X | X |
TypeScript | X |
而且Dart與Swift共享靠譜的空安全機(jī)制贝奇,其他語言可說不準(zhǔn)了虹菲。由于Dart的空安全機(jī)制很靠譜,它還可以令你的程序運(yùn)行得更快掉瞳。不但更安全毕源,而且更迅速。
各位程序員陕习,這對你來說代表什么呢霎褐???
我前面說過,大部分變量一定有某種類型的值该镣,絕不會沒有值冻璃,也就是說,他們不可為空损合。這是比較好懂的說法省艳。比"它們不可以有一個什么都沒有的值"好一點(diǎn)。
因此嫁审,你大部分的代碼應(yīng)該看起來像這樣: 沒有問好(?.
)跋炕,沒有空值判斷(!
),什么都沒有律适。
int fibonacci(int n) {
if (n <= 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
void main() {
print(fibonacci(10));
}
如果你覺得某個變量可能會出現(xiàn)空值辐烂,你就必須明確的標(biāo)識它可以為空。方法就是加上問好捂贿。
Color? favoriteColor
void setBackground(Color? color) {
// ...
}
Color? chooseFavorite() {
// ...
}
List<Color?> favorites;
它不但可以用在聲明變量的時候纠修,還可以用在函數(shù)參數(shù)、返回值厂僧,范型等等分瘾。
Dart還會幫助你避免跟空值有關(guān)的錯誤。基本上他會要你在適當(dāng)?shù)牡胤郊由峡罩禉z查德召,并且處理空值出現(xiàn)的情況。
void setBackground(Color? color) {
// ...
}
Color definitelyColor = Color(0xffff00ff);
setBackground(difinitelyColor); // 這是對的
你可能先前忘記處理了汽纤。如果是介于兩者之間的情況呢上岗?如果你將一個不可能為空的變量,傳給可空的字段蕴坪,是沒有問題的肴掷。
一個不可為空的顏色變量,可以傳給一個接受空值參數(shù)的函數(shù)背传,可是反過來的話呆瞻,就沒有那么簡單了。一個可為空的顏色變量径玖,就不可以傳給參數(shù)不可為空的函數(shù)痴脾。
void setBackground(Color color) {
// ...
}
Color? definitelyColor = null;
setBackground(definitelyColor); // 這是錯誤的
換句話說,如果你的函數(shù)說梳星,我不接受空值赞赖,我的參數(shù)都不可為空,你就不能將可能為空值的東西丟給它冤灾。這種情況怎么處理前域????
實(shí)踐
有幾種可能的做法。
- 完全不要調(diào)用這個函數(shù)韵吨,如果你知道變量是空值匿垄。
- 你知道變量是空值的,就改用別的變量归粉。提供默認(rèn)值椿疗。
- 使用感嘆號,強(qiáng)迫使用空值盏浇。這跟寫一段空值檢查很類似变丧。并在失敗時拋出異常。這個類雖可為空值绢掰,但你只有在100%確定這個變量不是空值的情況下才可以使用這個方法痒蓬。
setBackground(definitelyColor ?? black);
setBackground(definitelyColor!);
比如說滴劲,你知道這個程序的運(yùn)作背景攻晒,而Dart卻無從得知。不過大部分情況下班挖,<font color="red">你應(yīng)該盡量避免使用感嘆號鲁捏。</font>
就這樣,空安全令你的代碼更安全萧芙,運(yùn)行的更快速给梅,對你編寫方式的影響也降到最小假丧。
舊項(xiàng)目遷移
如果有興趣可以看下Dart提供了命令行工具,來轉(zhuǎn)化你的舊代碼到NullSafety的遷移动羽。
dart migrate
請到dart.dev/null-safety查閱更多資料