跳到主內容

運算子

Dart 支援下表中所示的運算子。該表從高到低顯示了 Dart 運算子的結合性和優先順序,這些是 Dart 運算子關係的近似值。你可以將許多這些運算子作為類成員實現

描述運算子結合性
一元后綴expr++    expr--    ()    []    ?[]    .    ?.    !
一元字首-expr    !expr    ~expr    ++expr    --expr      await expr
乘法*    /    %  ~/
加法+    -
移位<<    >>    >>>
位與&
位異或^
位或|
關係與型別測試>=    >    <=    <    as    is    is!
相等==    !=
邏輯與&&
邏輯或||
空值判斷??
條件expr1    ?    expr2    :    expr3
級聯..    ?..
賦值=    *=    /=   +=   -=   &=   ^=   等等
展開 (參見注釋)...    ...?

使用運算子時,會建立表示式。以下是運算子表示式的一些示例

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

運算子優先順序示例

#

運算子表中,每個運算子的優先順序都高於其下方行中的運算子。例如,乘法運算子 % 的優先順序高於(因此在其之前執行)相等運算子 ==,後者又高於邏輯與運算子 &&。這種優先順序意味著以下兩行程式碼的執行方式相同

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。

僅當你確定物件是該型別時,才使用 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,反之亦然)
||邏輯或
&&邏輯與

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

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

位與移位運算子

#

你可以在 Dart 中運算元字的單個位。通常,你會將這些位運算子和移位運算子與整數一起使用。

運算子含義
&
|
^異或
~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 運算子 ??(也稱為空值合併運算子)。

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)
!非空斷言運算子將表示式轉換為其底層非空型別,如果轉換失敗則丟擲執行時異常;示例:foo!.bar 斷言 foo 非空並選擇屬性 bar,除非 foo 為 null(在這種情況下會丟擲執行時異常)

有關 .?... 運算子的更多資訊,請參閱