跳至主要內容

運算子

Dart 支援下表所示的運算子。下表顯示 Dart 運算子的結合性和運算子優先順序,從最高到最低排列,這近似於 Dart 運算子的關係。您可以將許多這些運算子實作為類別成員

描述運算子結合性
一元後綴expr++    expr--    ()    []    ?[]    .    ?.    !
一元前綴-expr    !expr    ~expr    ++expr    --expr      await expr
乘法*    /    %  ~/向左
加法+    -向左
位移<<    >>    >>>向左
位元 AND&向左
位元 XOR^向左
位元 OR|向左
關係和類型測試>=    >    <=    <    as    is    is!
相等==    !=
邏輯 AND&&向左
邏輯 OR||向左
if-null??向左
條件expr1    ?    expr2    :    expr3向右
串聯..    ?..向左
賦值=    *=    /=   +=   -=   &=   ^=   等等向右
擴展 (請參閱附註)...    ...?

當您使用運算子時,您會建立運算式。以下是一些運算子運算式的範例

dart
a++
a + b
a = b
a == b
c ? a : b
a is T

運算子優先順序範例

#

運算子表格中,每個運算子的優先順序都高於後續列中的運算子。例如,乘法運算子 % 的優先順序高於 (因此執行順序先於) 相等運算子 ==,而相等運算子 == 的優先順序又高於邏輯 AND 運算子 &&。這種優先順序表示以下兩行程式碼的執行方式相同

dart
// Parentheses improve readability.
if ((n % i == 0) && (d % i == 0)) {
  // ...
}

// Harder to read, but equivalent.
if (n % i == 0 && d % i == 0) {
  // ...
}

算術運算子

#

Dart 支援常用的算術運算子,如下表所示。

運算子意義
+加法
-減法
-expr一元負號,也稱為負數 (反轉運算式的符號)
*乘法
/除法
~/除法,傳回整數結果
%取得整數除法的餘數 (模數)

範例

dart
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

Dart 也支援前綴和後綴遞增和遞減運算子。

運算子意義
++varvar  =  var + 1 (運算式值為 var + 1)
var++var  =  var + 1 (運算式值為 var)
--varvar  =  var - 1 (運算式值為 var - 1)
var--var  =  var - 1 (運算式值為 var)

範例

dart
int a;
int b;

a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++; // Increment a after b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--; // Decrement a after b gets its value.
assert(a != b); // -1 != 0

相等和關係運算子

#

下表列出相等和關係運算子的意義。

運算子意義
==等於;請參閱以下討論
!=不等於
>大於
<小於
>=大於或等於
<=小於或等於

若要測試兩個物件 x 和 y 是否代表相同的事物,請使用 == 運算子。(在極少數情況下,您需要知道兩個物件是否完全是相同的物件,請改用 identical() 函式。) 以下說明 == 運算子的運作方式

  1. 如果 xy 為 null,則如果兩者皆為 null,則傳回 true,如果只有一個為 null,則傳回 false。

  2. 傳回在 x 上以引數 y 叫用 == 方法的結果。(沒錯,== 等運算子是在其第一個運算元上叫用的方法。如需詳細資訊,請參閱運算子。)

以下是使用每個相等和關係運算子的範例

dart
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

類型測試運算子

#

asisis! 運算子對於在執行階段檢查類型非常方便。

運算子意義
as類型轉換 (也用於指定程式庫前綴)
is如果物件具有指定的類型,則為 true
is!如果物件不具有指定的類型,則為 true

如果 obj 實作 T 指定的介面,則 obj is T 的結果為 true。例如,obj is Object? 永遠為 true。

如果您確定物件屬於 T 類型,才使用 as 運算子將物件轉換為特定類型。範例

dart
(employee as Person).firstName = 'Bob';

如果您不確定物件是否為 T 類型,則在使用物件之前,請先使用 is T 檢查類型。

dart
if (employee is Person) {
  // Type check
  employee.firstName = 'Bob';
}

賦值運算子

#

如您所見,您可以使用 = 運算子賦值。若要僅在賦值變數為 null 時才賦值,請使用 ??= 運算子。

dart
// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;

複合賦值運算子 (例如 +=) 將運算與賦值結合在一起。

=*=%=>>>=^=
+=/=<<=&=|=
-=~/=>>=

以下說明複合賦值運算子的運作方式

複合賦值等效運算式
對於運算子 opa op= ba = a op b
範例a += ba = a + b

以下範例使用賦值和複合賦值運算子

dart
var a = 2; // Assign using =
a *= 3; // Assign and multiply: a = a * 3
assert(a == 6);

邏輯運算子

#

您可以使用邏輯運算子反轉或組合布林運算式。

運算子意義
!expr反轉下列運算式 (將 false 變更為 true,反之亦然)
||邏輯 OR
&&邏輯 AND

以下是使用邏輯運算子的範例

dart
if (!done && (col == 0 || col == 3)) {
  // ...Do something...
}

位元運算子和位移運算子

#

您可以在 Dart 中操作數字的個別位元。通常,您會將這些位元運算子和位移運算子與整數搭配使用。

運算子意義
&AND
|OR
^XOR
~expr一元位元補數 (0 變成 1;1 變成 0)
<<向左位移
>>向右位移
>>>不帶正負號的向右位移

以下是使用位元運算子和位移運算子的範例

dart
final value = 0x22;
final bitmask = 0x0f;

assert((value & bitmask) == 0x02); // AND
assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR

assert((value << 4) == 0x220); // Shift left
assert((value >> 4) == 0x02); // Shift right

// Shift right example that results in different behavior on web
// because the operand value changes when masked to 32 bits:
assert((-value >> 4) == -0x03);

assert((value >>> 4) == 0x02); // Unsigned shift right
assert((-value >>> 4) > 0); // Unsigned shift right

條件運算式

#

Dart 有兩個運算子可讓您簡潔地評估運算式,否則可能需要 if-else 陳述式

condition ? expr1 : expr2
如果 condition 為 true,則評估 expr1 (並傳回其值);否則,評估並傳回 expr2 的值。
expr1 ?? expr2
如果 expr1 為非 null,則傳回其值;否則,評估並傳回 expr2 的值。

當您需要根據布林運算式賦值時,請考慮使用條件運算子 ?:

dart
var visibility = isPublic ? 'public' : 'private';

如果布林運算式測試 null,請考慮使用 if-null 運算子 ?? (也稱為 null 聯合運算子)。

dart
String playerName(String? name) => name ?? 'Guest';

先前的範例至少可以用另外兩種方式撰寫,但不如這種方式簡潔

dart
// Slightly longer version uses ?: operator.
String playerName(String? name) => name != null ? name : 'Guest';

// Very long version uses if-else statement.
String playerName(String? name) {
  if (name != null) {
    return name;
  } else {
    return 'Guest';
  }
}

串聯表示法

#

串聯 (..?..) 可讓您對同一個物件執行一系列運算。除了存取執行個體成員之外,您也可以對同一個物件呼叫執行個體方法。這通常可以省去建立暫時變數的步驟,並讓您撰寫更流暢的程式碼。

請考慮以下程式碼

dart
var paint =
    Paint()
      ..color = Colors.black
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 5.0;

建構式 Paint() 會傳回 Paint 物件。串聯表示法之後的程式碼會對此物件進行運算,忽略可能傳回的任何值。

先前的範例等效於此程式碼

dart
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;

如果串聯運算作用的物件可能為 null,則對第一個運算使用空值短路串聯 (?..)。從 ?.. 開始可保證不會對該 null 物件嘗試任何串聯運算。

dart
document.querySelector('#confirm') // Get an object.
  ?..textContent =
      'Confirm' // Use its members.
  ..classList.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

先前的程式碼等效於以下程式碼

dart
final button = document.querySelector('#confirm');
button?.textContent = 'Confirm';
button?.classList.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();

您也可以巢狀串聯。例如

dart
final addressBook =
    (AddressBookBuilder()
          ..name = 'jenny'
          ..email = 'jenny@example.com'
          ..phone =
              (PhoneNumberBuilder()
                    ..number = '415-555-0100'
                    ..label = 'home')
                  .build())
        .build();

請小心在傳回實際物件的函式上建構串聯。例如,以下程式碼會失敗

dart
var sb = StringBuffer();
sb.write('foo')
  ..write('bar'); // Error: method 'write' isn't defined for 'void'.

sb.write() 呼叫傳回 void,而且您無法在 void 上建構串聯。

擴展運算子

#

擴展運算子會評估產生集合的運算式、解壓縮產生的值,並將其插入另一個集合中。

擴展運算子實際上不是運算子運算式.../...? 語法是集合常值本身的一部分。因此,您可以在集合頁面上瞭解更多關於擴展運算子的資訊。

由於它不是運算子,因此語法沒有任何「運算子優先順序」。實際上,它具有最低的「優先順序」— 任何類型的運算式都可作為擴展目標,例如

dart
[...a + b]

其他運算子

#

您已在其他範例中看過其餘的大部分運算子

運算子名稱意義
()函式應用表示函式呼叫
[]下標存取表示對可覆寫的 [] 運算子的呼叫;範例:fooList[1] 將整數 1 傳遞至 fooList 以存取索引 1 處的元素
?[]條件式下標存取類似於 [],但最左邊的運算元可以是 null;範例:fooList?[1] 將整數 1 傳遞至 fooList 以存取索引 1 處的元素,除非 fooList 為 null (在這種情況下,運算式評估為 null)
.成員存取參照運算式的屬性;範例:foo.bar 從運算式 foo 選取屬性 bar
?.條件式成員存取類似於 .,但最左邊的運算元可以是 null;範例:foo?.bar 從運算式 foo 選取屬性 bar,除非 foo 為 null (在這種情況下,foo?.bar 的值為 null)
!非 null 斷言運算子將運算式轉換為其基礎的非可 null 類型,如果轉換失敗,則擲回執行階段例外狀況;範例:foo!.bar 斷言 foo 為非 null,並選取屬性 bar,除非 foo 為 null,在這種情況下,會擲回執行階段例外狀況

如需關於 .?... 運算子的詳細資訊,請參閱類別