前言
對於每一個程式設計師來說,空指標異常應該是基本都會遇到過的異常,而且這個異常出現的概率還比較大。
但是,空指標異常又是最容易解決的異常,因為只要加個非空判斷就可以避免了。
本篇通過對比一般非空判斷和 dart 特有的語法糖告訴你如何使用 dart 進行優雅的避空。
目錄
1. dart 線上編輯器
一般一些簡單的 dart 測試我們可以直接用線上編輯器來做測試和驗證。
下面給大家介紹的兩個都是官網的。
dart 線上執行器主頁版: ?
www.dartlang.org/guides/get-…
dart 線上執行器全屏版: ?
dartpad.dartlang.org/null
其中全屏版就是在主頁版裡面點選全屏按鈕就開啟了。
所以可以認為是一樣的。
但是筆者使用起來的不同如下,大家可以根據自己的感受選擇。
主頁版:
優點:執行輸出結果較全屏版快。
缺點:輸出結果區域較小,超出需要滑動檢視。
全屏版:
優點:輸出結果區域大。可以直觀看到結果。
缺點:執行輸出結果較主頁版慢。
2. dart ?.
dart 語法糖 ?.
它的意思是左邊如果為空返回 null,否則返回右邊的值。
A?.B
如果 A 等於 null,那麼 A?.B 為 null
如果 A 不等於 null,那麼 A?.B 等價於 A.B
Sample:
void main() {
Animal animal = new Animal('cat');
Animal empty = null;
//animal 非空,返回 animal.name 的值 cat
print(animal?.name);
//empty 為空,返回 null
print(empty?.name);
//animal 非空,可以直接訪問 animal.name 的值 cat
print(animal.name);
//empty 為空,丟擲異常
print(empty.name);
}
class Animal {
final String name;
Animal(this.name);
}
複製程式碼
大家拷貝程式碼然後替換線上編輯器的內容,執行後會看到如下輸出:
cat
null
cat
Uncaught exception:
Cannot read property 'get$name' of null
複製程式碼
可以看到假設左邊不為空,不管是使用**?.還是直接用我們熟悉的.訪問變數都是沒問題的。
但是如果左邊為空,使用?.會返回null**。但是直接使用**.**會直接丟擲異常。
3. dart ??
dart 語法糖 ??
它的意思是左邊如果為空返回右邊的值,否則不處理。
A??B
如果 A 等於 null,那麼 A??B 為 B
如果 A 不等於 null,那麼 A??B 為 A
以上面為例子,假設我們上面要求當 empty 為空時,預設值輸出 unknown。
那麼可以修改如下:
//empty 為空,返回 null
print(empty?.name);
複製程式碼
改為
//empty 為空,本來要返回 null,由於有 ??,返回 unknown
print(empty?.name??'unknown');
複製程式碼
這樣就不會返回 null 而是返回 unknown。
同樣的大家可以試下返回 cat 的語句如果加上這個會怎樣,可以預見是不會改變的。
4. dart ?. ?? 優雅所在
這邊舉例說明下使用 ?. ?? 語法糖和不使用的對比。
void main() {
C c = new C('Case 1');
B b = new B(c);
A a = new A(b);
// C c = new C(null);
// B b = new B(c);
// A a = new A(b);
// C c = new C('Case 2');
// B b = null;
// A a = new A(b);
//直接使用.來最終獲取 c 的變數 value
if (a != null && a.bMember != null && a.bMember.cMember != null) {
print(a.bMember.cMember.value);
} else {
print(null);
}
//直接使用.來最終獲取 c 的變數 value,為空時返回 unknown
if (a != null && a.bMember != null && a.bMember.cMember != null) {
String value = a.bMember.cMember.value;
if (value == null) {
value = 'unknown';
}
print(value);
} else {
print('unknown');
}
//dart 使用?.來最終獲取 c 的變數 value
print(a?.bMember?.cMember?.value);
//dart 使用?.來最終獲取 c 的變數 value,為空時使用 ?? 返回 unknown
print(a?.bMember?.cMember?.value??'unknown');
}
class A {
final B bMember;
A(this.bMember);
}
class B {
final C cMember;
B(this.cMember);
}
class C {
final String value;
C(this.value);
}
複製程式碼
這裡面有三個 case,另外兩個 case 暫時註釋掉。
這三個 case 的結果分別為:
Case 1
Case 1
Case 1
Case 1
複製程式碼
null
unknown
null
unknown
複製程式碼
null
unknown
null
unknown
複製程式碼
可以看到 dart 的語法糖很優雅,一行全搞定。
5. print 方法遇到 null
下面這個例子:
void main() {
String a = null;
print('exception='+a);
}
複製程式碼
你覺得結果是 exception=null 嗎?
結果是
Uncaught exception:
Invalid argument: null
複製程式碼
原因是因為 print 裡面連線的必須是字串。
因為這裡 a 確實是字串,所以編輯器沒有報錯。
假設這裡 a 為一個物件 A 的變數,會報如下提示:
The argument type 'A' can't be assigned to the parameter type 'String'.
複製程式碼
那我們怎麼處理?
有兩種方法。
方法一:
void main() {
String a = null;
print('exception='+'$a');
}
複製程式碼
方法二:
void main() {
String a = null??'null';
print('exception='+a);
}
複製程式碼
注意下面的寫法是不行的,原因是 ?? 優先順序沒有 + 高。需要加小括號。
void main() {
String a = null;
print('exception='+a??'null');
}
複製程式碼
6. 牛刀小試
知識學以致用才能夠鞏固。
因此這邊出了小題目給大家測試是否完全掌握本篇內容。
答案組成了支付寶口令紅包哦~
微信公眾號回覆「牛刀小試」獲取題目。
或者直接點選選單欄目錄->牛刀小試獲取。
溫馨提示:
如果你輸入 3 次還是提示錯誤(錯誤過多口令紅包會暫時不可用哦),有兩種情況。
第一種就是答案錯了。
第二種就是領取完了。
答案會在紅包領取完之後或一天之後將題目替換為題目+答案。
因為是非同步的,所以不一定實時更新哦~
更多閱讀:
Flutter 即學即用系列部落格——01 環境搭建
Flutter 即學即用系列部落格——02 一個純 Flutter Demo 說明
Flutter 即學即用系列部落格——03 在舊有專案引入 Flutter
Flutter 即學即用系列部落格——04 Flutter UI 初窺
Flutter 即學即用系列部落格——05 StatelessWidget vs StatefulWidget