Dart 串聯運算子

串聯語法分為兩種:..?..

針對同一個物件連續執行多個屬性指派、方法呼叫,不用宣告暫存變數,程式碼更連貫好讀。

串聯語法並非運算子,是 Dart 專屬的語法糖。

1. 一般串聯 ..

確認物件一定不為 null時使用

所有 .. 的操作都會作用在一開頭的原始物件,忽略每一步方法回傳的數值。

官方示範

import 'dart:ui';

void main() {
  // 串聯寫法
  var paint = Paint()
    ..color = Colors.black
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 5.0;

  // 拆開對等寫法(不使用串聯,需重複變數名稱)
  var paint2 = Paint();
  paint2.color = Colors.black;
  paint2.strokeCap = StrokeCap.round;
  paint2.strokeWidth = 5.0;
}Code language: JavaScript (javascript)

這個範例匯入 dart:ui 程式庫,屬於 Flutter 專用程式庫,只能在 Flutter 專案執行。我們現在學習純 Dart,讀者只需看懂語法即可;下方改用純 Dart 內建類別 StringBuffer 示範:

StringBuffer 是專門處理字串操作的類別

void main() {
  // 串聯語法示範
  var sb = StringBuffer()
    ..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());

  // 不使用串聯的對等寫法
  var sb2 = StringBuffer();
  sb2.write("Hello ");
  sb2.write("FoxDevelop.com ");
  sb2.writeln("Cascade");
  print(sb2.toString());
}Code language: PHP (php)

執行輸出

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Hello FoxDevelop.com Cascade

Hello FoxDevelop.com CascadeCode language: CSS (css)

上面的 paint、sb、sb2 這類物件,只要能確保絕對不為 null,就可以用串聯快速指派屬性,不用重複書寫物件名稱呼叫屬性。但如果物件是 null,直接執行會報錯。

void main() {

  var sb = null
    ..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());
}Code language: JavaScript (javascript)

因此提供第二種寫法來處理空值場景

2. 空值安全串聯 ?..

只要物件是 null,整串串聯鏈全部不執行,避免空指標錯誤;僅串聯開頭使用 ?..,後續直接接 ..

void main() {

  var sb = null
    ?..write("Hello ")
    ..write("FoxDevelop.com ")
    ..writeln("Cascade");

  print(sb.toString());
}Code language: Dart (dart)

留意第一行是 ?..write(“Hello “),前面多一個問號

重新執行編譯可正常執行,不會拋錯

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
nullCode language: CSS (css)

程式不會報錯

下方為官方示範,讀者認識語法格式即可

// 開頭使用 ?..,後續一律使用 ..
document.querySelector('#confirm')
  ?..textContent = 'Confirm'
  ..classList.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

// 對等的空安全拆分寫法
final button = document.querySelector('#confirm');
button?.textContent = 'Confirm';
button?.classList.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();Code language: JavaScript (javascript)

巢狀串聯

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      // 內層 PhoneNumberBuilder 獨立使用串聯
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();Code language: PHP (php)

phone 屬性會建立 PhoneNumberBuilder 物件並指派給它。

注意事項

串聯語法只能作用於物件實體,不能接在回傳 void 的方法後,否則會編譯錯誤。

var sb = StringBuffer();
sb.write('foo') // write 方法回傳 void
  ..write('bar'); // 報錯:void 型別沒有 write 方法Code language: Dart (dart)

這段程式先建立 StringBuffer 物件 sb

這裡用分號結束了 sb.write(‘foo’),而 write 回傳值是 void,後續就不能再接 ..write;只有當方法回傳物件實體時,才能繼續串聯。

正確寫法

var sb = StringBuffer()
  ..write('foo')
  ..write('bar');Code language: Dart (dart)

重點整理

  1. .. 每一次操作都會回到最頂層原始物件,忽略方法回傳值,可連續串接,類似其他程式語言的鏈式呼叫(例如 JavaScript)
  2. ?.. 空值安全串聯,避免物件為 null 時發生錯誤,僅需在串聯開頭使用;只要開頭能執行,就代表物件不為 null,後續不需再加問號
  3. 支援巢狀多層串聯
  4. 不可在回傳 void 的方法後使用串聯
  5. .. 不屬於運算子,是 Dart 提供的語法糖
何謂語法糖

語法糖是程式語言在解析階段,針對相同底層邏輯提供的簡寫語法;不會新增任何語言功能,編譯器/直譯器產生中間程式碼前,會自動將簡寫還原為標準基礎程式碼。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *