dart 如何優雅的避空


前言

對於每一個程序員來說,空指針異常應該是基本都會遇到過的異常,而且這個異常出現的概率還比較大。

但是,空指針異常又是最容易解決的異常,因為只要加個非空判斷就可以避免了。

本篇通過對比一般非空判斷和 dart 特有的語法糖告訴你如何使用 dart 進行優雅的避空。

目錄

1. dart 在線編輯器

一般一些簡單的 dart 測試我們可以直接用在線編輯器來做測試和驗證。

下面給大家介紹的兩個都是官網的。

dart 在線運行器主頁版:👇
https://www.dartlang.org/guides/get-started

dart 在線運行器全屏版:👇
https://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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM