iT邦幫忙

2024 iThome 鐵人賽

0
Mobile Development

Flutter 開發實戰 - 30 天逃離新手村系列 第 37

番外篇 - 理解模式與解構

  • 分享至 

  • xImage
  •  

初學 Dart 如果你常常被一些魔法般的程式碼困惑,很可能是沒有深入理解模式的概念。模式(Pattern)是 Dart 3.0 引入的一個重要特性,模式 pattern 的概念主要是涉及「比對」match 和「解構」destructure 。準確的說就是可以實現「比對」或「解構」的語法,類似於語句 statement 和表達式 expression。可以把模式想成是一個資料的模板,具備特定結構,我們可以用來比對是否符合結構,進一步解構取得值。

許多新語言都支援類似模式的概念,例如 Swift ,Kotlin 的解構和 when。粗略來說我們可以把模式概念理解為一種 switch-case case 條件的進化版。

模式在 Dart 中主要用於兩個目的:比對和解構。

  • 比對:或叫匹配,檢查一個值是否符合某種特定的結構或條件。
  • 解構:從一個複雜的資料結構中提取出特定的部分。

具體來說,模式本身有很多類型可以協助我們比對各種類型的資料:

  • 常數模式:也就是我們常見用 swtich 比對某個值例如 nulltrue'abc'
  • 變數模式:綁定值到變數 var x
  • 列表模式:例如 ['a' || 'b', var c] ,匹配一個值是一有兩個元素的列表,第一個元素需要是 a 或 b,而 var c 則是變數模式,任何值可以綁定到變數 c。
  • Map 模式:例如 {"name": String name } 匹配特定鍵值對
  • 物件模式:比對值是否為某個類別的物件 Person(:name),也可以進一步比對屬性。物件模式看起來像是預設建構子,甚至該類別沒有預設建構子也是一樣的撰寫方式,更多例子如 String()int()
  • Wildcard 萬用字元模式: _ 任何值都匹配
  • Record 模式:例如 (1, int y) ,一個常數和變數型別模式組合而成的 Record

從列表模式的範例我們知道模式是可以和邏輯運算子搭配使用的,包含 &&|| 以及 () 類似表達式。如此可以增加比對匹配的複雜性和靈活性

根據模式出現的位置提供比對或解構的功能:

var nums = [1 ,2 ,3];
var [a, b, c] = nums;

switch (list) {
  case ['a' || 'b', var c]:
    print(c);
}

接著,我們進一步瞭解模式可能出現的位置:

  • 變數的宣告和設定位置
  • forfor-in 迴圈
  • if-caseswtich-case
  • 集合
// 變數宣告
var (a, [b, c]) = ('A', [1, 2]); // 模式變數須使用 `var` 或 `final` 開頭。
(b, a) = (a, b); // 交換

// switch
// 模式在 case 中的解構值會變成區域變數,只限於該 case 範圍內
switch (obj) {
  case 1:
  // 如果 obj 大於等於 2 小於等於 5
  case >= 2 && <= 5:
  // 如果 obj 是一個 2 個元素的 Record
  case (var x, var y):
}

// 邏輯或模式
var isOdd = switch (n) {
    1 || 3 || 5 => true,
    _ => false
}

// 搭配 when
switch (shape) {
  case Square(size: var s) || Circle(size: var s) when s > 0:
    //
}
switch (pair) {
  case (int a, int b) when a > b:
    // 
}

在某些情況下,模式匹配可能失敗,但不會導致錯誤,而是繼續執行下一個選項。這種情況稱為 Refutable context。例如,switch 語句和 if-case 語句中的模式就是在 Refutable context 中。

User? fromJson(Map<String, Object?> data) => switch(data) {
  {'username': String name, 'age': int age} => User(
    username: name,
    age: age,
  ),
  _ => null,
};

bool isUnitCircle(Object? data) {
  if (data case Circle(radius: var rad) when rad ==1) {
   return true;
  }
  return false;
}

有了模式的概念很多東西就比較容易理解。例如 if-case 的 case 我們可以想成原本只能用 ==!= 等邏輯運算子,現在可以通過 case 直接使用模式比對

// 如果沒有 case
if (pair is List && 
    pair.length == 2 && 
    pair[0] is int && 
    pair[1] is int) {
  return Point(pair[0] as int, pair[1] as int);
}

// case 版本
if (pair case [int x, int y]) return Point(x, y);

上一篇
Shorebird - Flutter 版 Code Push
下一篇
番外篇 - 快速複習類別
系列文
Flutter 開發實戰 - 30 天逃離新手村38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言