Dart 支持下表中所示的運算符。
該表按從高到低的順序顯示了 Dart 的運算符結合性和 運算符優先級 ,這只是 Dart 運算符關係的 近似值 。
您可以將許多這些 運算符實現為類成員 。
| 描述 | 運算符 | 結合性 |
|---|---|---|
| 一元后綴 | expr++ expr-- () [] ?[] . ?. ! |
無 |
| 一元前綴 | -expr !expr ~expr ++expr --expr await expr |
無 |
| 乘法 | * / % ~/ |
左結合 |
| 加法 | + - |
左結合 |
| 移位 | << >> >>> |
左結合 |
| 按位與 | & |
左結合 |
| 按位異或 | ^ |
左結合 |
| 按位或 | | |
左結合 |
| 關係和類型測試 | >= > <= < as is is! |
無 |
| 等式 | == != |
無 |
| 邏輯與 | && |
左結合 |
| 邏輯或 | || |
左結合 |
| 空值合併 | ?? |
左結合 |
| 條件 | expr1 ? expr2 : expr3 |
右結合 |
| 級聯 | .. ?.. |
左結合 |
| 賦值 | = *= /= += -= &= ^= _etc._ |
右結合 |
| 展開 (參見注釋) | ... ...? |
無 |
警告
上表僅供參考。
運算符優先級和結合性的概念是對語言語法中真實情況的近似。
您可以在 Dart 語言規範 中定義的語法中找到 Dart 運算符關係的權威行為。
使用運算符時,您會創建表達式。以下是一些運算符表達式的示例:
a++
a + b
a = b
a == b
c ? a : b
a is T
運算符優先級示例
在 運算符表 中,
每個運算符的優先級都高於其後行的運算符。例如,乘法運算符 % 的優先級高於(因此在執行之前)等於運算符 == ,而 == 的優先級高於邏輯與運算符 && 。
這種優先級意味着以下兩行代碼的執行方式相同:
// 括號提高了可讀性。
if ((n % i == 0) && (d % i == 0)) ...
// 更難閲讀,但等效。
if (n % i == 0 && d % i == 0) ...
警告
對於採用兩個操作數的運算符,最左邊的操作數決定使用哪種方法。例如,如果您有一個Vector對象和一個Point對象,則aVector + aPoint使用Vector加法 (+)。
算術運算符
Dart 支持常用的算術運算符,如下表所示。
| 運算符 | 含義 |
|---|---|
+ |
加 |
- |
減 |
-expr |
一元負號,也稱為否定(反轉表達式的符號) |
* |
乘 |
/ |
除 |
~/ |
除,返回整數結果 |
% |
獲取整數除法的餘數(模) |
示例:
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 結果是 double
assert(5 ~/ 2 == 2); // 結果是 int
assert(5 % 2 == 1); // 餘數
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Dart 還支持前綴和後綴自增和自減運算符。
| 運算符 | 含義 |
|---|---|
++var |
var = _var + 1 (表達式的值為 var_ + 1) |
var++ |
var = _var + 1 (表達式的值為 var_) |
--var |
var = _var - 1 (表達式的值為 var_ - 1) |
var-- |
var = _var - 1 (表達式的值為 var_) |
示例:
int a;
int b;
a = 0;
b = ++a; // 在 b 獲取其值之前遞增 a。
assert(a == b); // 1 == 1
a = 0;
b = a++; // 在 b 獲取其值之後遞增 a。
assert(a != b); // 1 != 0
a = 0;
b = --a; // 在 b 獲取其值之前遞減 a。
assert(a == b); // -1 == -1
a = 0;
b = a--; // 在 b 獲取其值之後遞減 a。
assert(a != b); // -1 != 0
等式和關係運算符
下表列出了等式和關係運算符的含義。
| 運算符 | 含義 |
|---|---|
== |
等於;見下文討論 |
!= |
不等於 |
> |
大於 |
< |
小於 |
>= |
大於或等於 |
<= |
小於或等於 |
要測試兩個對象 x 和 y 是否表示相同的事物,請使用 == 運算符。(在極少數情況下,如果您需要知道兩個對象是否是完全相同的對象,請改用 identical() 函數。)以下是 == 運算符的工作原理:
- 如果 x 或 y 為 null,則如果兩者都為 null,則返回 true,如果只有一個為 null,則返回 false。
- 返回在 x 上調用
==方法並使用參數 y 的結果。(沒錯,像==這樣的運算符是在其第一個操作數上調用的方法。有關詳細信息,請參閲 運算符 。)
以下是使用每個等式和關係運算符的示例:
<?code-excerpt "misc/test/language\_tour/operators\_test.dart (relational)"?>
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
類型測試運算符
as 、 is 和 is! 運算符非常方便,用於在運行時檢查類型。
| 運算符 | 含義 |
|---|---|
as |
類型轉換(也用於指定 庫前綴 ) |
is |
如果對象具有指定的類型,則為 true |
is! |
如果對象不具有指定的類型,則為 true |
obj is T 的結果如果 obj 實現 T 指定的接口則為 true。例如, obj is Object? 總是為 true。
僅當您確定對象屬於該類型時,才使用 as 運算符將對象轉換為特定類型。示例:
(employee as Person).firstName = 'Bob';
如果您不確定對象是否為 T 類型,則在使用對象之前使用 is T 檢查類型。
if (employee is Person) {
// 類型檢查
employee.firstName = 'Bob';
}
注意
代碼不等效。如果employee為 null 或不是Person,則第一個示例會拋出異常;第二個示例什麼也不做。
賦值運算符
如您所見,您可以使用 = 運算符賦值。
要僅在被賦值變量為 null 時賦值,
請使用 ??= 運算符。
// 將值賦給 a
a = value;
// 如果 b 為 null,則將值賦給 b;否則,b 保持不變
b ??= value;
諸如 += 之類的複合賦值運算符將運算與賦值結合起來。
| | | | | |
|---|---|---|---|---|
= |
*= |
%= |
>>>= |
^= |
+= |
/= |
<<= |
&= |
|= |
-= |
~/= |
>>= |
| |
以下是複合賦值運算符的工作原理:
| | 複合賦值 | 等效表達式 |
|---|---|---|
| 對於運算符 _op_: | a op= b |
a = a op b |
| 示例: | a += b |
a = a + b |
以下示例使用了賦值和複合賦值運算符:
var a = 2; // 使用 = 賦值
a *= 3; // 賦值並乘:a = a * 3
assert(a == 6);
邏輯運算符
您可以使用邏輯運算符反轉或組合布爾表達式。
| 運算符 | 含義 |
|---|---|
!expr |
反轉後面的表達式(將 false 更改為 true,反之亦然) |
|| |
邏輯或 |
&& |
邏輯與 |
以下是使用邏輯運算符的示例:
if (!done && (col == 0 || col == 3)) {
// ...執行某些操作...
}
位運算符和移位運算符
您可以操作 Dart 中數字的各個位。通常,您會將這些位運算符和移位運算符與整數一起使用。
| 運算符 | 含義 |
|---|---|
& |
與 |
| |
或 |
^ |
異或 |
~expr |
一元按位取反(0 變成 1;1 變成 0) |
<< |
左移 |
>> |
右移 |
>>> |
無符號右移 |
備註
使用大操作數或負操作數的位運算的行為可能因平台而異。
要了解更多信息,請查看 位運算平台差異 。
以下是使用位運算符和移位運算符的示例:
final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); // 與
assert((value & ~bitmask) == 0x20); // 與非
assert((value | bitmask) == 0x2f); // 或
assert((value ^ bitmask) == 0x2d); // 異或
assert((value << 4) == 0x220); // 左移
assert((value >> 4) == 0x02); // 右移
// 右移示例,在 Web 上的結果行為不同,
// 因為操作數的值在掩碼為 32 位時會發生變化:
assert((-value >> 4) == -0x03);
assert((value >>> 4) == 0x02); // 無符號右移
assert((-value >>> 4) > 0); // 無符號右移
注意版本
>>>運算符(稱為 三元移位 或 無符號移位 )需要至少 2.14 的 語言版本 。
條件表達式
Dart 有兩個運算符,允許您簡潔地計算否則可能需要 if-else 語句的表達式:
condition_ ? expr1 : expr2_
: 如果 condition 為 true,則計算 _expr1_(並返回其值);
否則,計算並返回 expr2 的值。
_expr1 ?? expr2_
: 如果 expr1 不為 null,則返回其值;
否則,計算並返回 expr2 的值。
當您需要根據布爾表達式賦值時,
請考慮使用條件運算符 ? 和 : 。
var visibility = isPublic ? 'public' : 'private';
如果布爾表達式測試 null 值,
請考慮使用空值合併運算符 ??
(也稱為空值合併運算符)。
String playerName(String? name) => name ?? 'Guest';
前面的示例可以用至少另外兩種方式編寫,
但沒有那麼簡潔:
// 稍長的版本使用 ?: 運算符。
String playerName(String? name) => name != null ? name : 'Guest';
// 很長的版本使用 if-else 語句。
String playerName(String? name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
級聯表示法
級聯( .. , ?.. )允許您對同一對象執行一系列操作。除了訪問實例成員外,您還可以對同一對象調用實例方法。這通常可以節省您創建臨時變量的步驟,並允許您編寫更流暢的代碼。
考慮以下代碼:
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
構造函數 Paint()
返回一個 Paint 對象。
級聯表示法後面的代碼對該對象進行操作,忽略任何可能返回的值。
前面的示例等效於以下代碼:
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;
如果級聯操作的對象可能為 null,
則對第一個操作使用 空值簡寫 級聯( ?.. )。
以 ?.. 開頭可以保證不會對該 null 對象嘗試任何級聯操作。
querySelector('#confirm') // 獲取對象。
?..text = 'Confirm' // 使用其成員。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'))
..scrollIntoView();
注意版本
?..語法需要至少 2.12 的 語言版本 。
前面的代碼等效於以下代碼:
var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();
您還可以嵌套級聯。例如:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
小心地在一個返回實際對象的函數上構建級聯。例如,以下代碼會失敗:
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // 錯誤:方法 'write' 未為 '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 不為 null 並選擇屬性 bar ,除非 foo 為 null,在這種情況下會拋出運行時異常 |
有關 . 、 ?. 和 .. 運算符的更多信息,請參閲 類 。
來源:dart 中文開發文檔