博客 / 詳情

返回

Dart 運算符

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() 函數。)以下是 == 運算符的工作原理:

  1. 如果 xy 為 null,則如果兩者都為 null,則返回 true,如果只有一個為 null,則返回 false。
  2. 返回在 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);

類型測試運算符

asisis! 運算符非常方便,用於在運行時檢查類型。

運算符 含義
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;

諸如 += 之類的複合賦值運算符將運算與賦值結合起來。

= *= %= >>>= ^=
+= /= <<= &= &#124;=
-= ~/= >>=

以下是複合賦值運算符的工作原理:

複合賦值 等效表達式
對於運算符 _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 中數字的各個位。通常,您會將這些位運算符和移位運算符與整數一起使用。

運算符 含義
&
&#124;
^ 異或
~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 中文開發文檔

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.