作者 | 弗拉德
來(lái)源 | 弗拉德(公眾號(hào):fulade_me)
運(yùn)算符
運(yùn)算符是一種告訴編譯器執(zhí)行特定的數(shù)學(xué)或邏輯操作的符號(hào)。Dart語(yǔ)言?xún)?nèi)置了豐富的運(yùn)算符,并提供了以下類(lèi)型的運(yùn)算符:算術(shù)運(yùn)算符、關(guān)系運(yùn)算符、類(lèi)型判斷運(yùn)算符、賦值運(yùn)算符、邏輯運(yùn)算符、按位和移位運(yùn)算符、條件表達(dá)式、級(jí)聯(lián)運(yùn)算符以及其他運(yùn)算符。
算數(shù)運(yùn)算符
| 算數(shù)運(yùn)算符 | 描述 |
|---|---|
| + | 加 |
| - | 減 |
| - 表達(dá)式 | 一元負(fù), 也可以作為反轉(zhuǎn)(反轉(zhuǎn)表達(dá)式的符號(hào)) |
| * | 乘 |
| / | 除 |
| ~/ | 除并取整 |
| % | 取模 |
示例:
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 結(jié)果是一個(gè)浮點(diǎn)數(shù)
assert(5 ~/ 2 == 2); // 結(jié)果是一個(gè)整數(shù)
assert(5 % 2 == 1); // 取余
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Dart 還支持自增自減運(yùn)算符:
| 自增自減運(yùn)算符 | 描述 |
|---|---|
| ++ var | var = var + 1 (表達(dá)式的值為 var + 1) |
| var ++ | var = var + 1 (表達(dá)式的值為 var) |
| -- var | var = var – 1 (表達(dá)式的值為 var – 1) |
| var -- | var = var – 1 (表達(dá)式的值為 var) |
示例:
var a, b;
a = 0;
b = ++a; // 在 b 賦值前將 a 增加 1。
assert(a == b); // 1 == 1
a = 0;
b = a++; // 在 b 賦值后將 a 增加 1。
assert(a != b); // 1 != 0
a = 0;
b = --a; // 在 b 賦值前將 a 減少 1。
assert(a == b); // -1 == -1
a = 0;
b = a--; // 在 b 賦值后將 a 減少 1。
assert(a != b); // -1 != 0
關(guān)系運(yùn)算符
| 關(guān)系運(yùn)算符 | 描述 |
|---|---|
| == | 相等 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
要判斷兩個(gè)對(duì)象 x 和 y 是否表示相同的事物使用 == 即可。(在極少數(shù)情況下,可能需要使用 identical() 函數(shù)來(lái)確定兩個(gè)對(duì)象是否完全相同)。
下面是 == 運(yùn)算符的一些規(guī)則:
假設(shè)有變量
x和y,且x和y至少有一個(gè)為null,則當(dāng)且僅當(dāng)x和y均為null時(shí)x == y才會(huì)返回true,否則只有一個(gè)為null則返回false。x.==(y)將會(huì)返回值,這里不管有沒(méi)有y,即y是可選的。也就是說(shuō)==其實(shí)是x中的一個(gè)方法,并且可以被重寫(xiě)。
下面的代碼給出了每一種關(guān)系運(yùn)算符的示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
類(lèi)型判斷運(yùn)算符
as、is、is! 運(yùn)算符是在運(yùn)行時(shí)判斷對(duì)象類(lèi)型的運(yùn)算符。
| 類(lèi)型判斷運(yùn)算符 | 描述 |
|---|---|
| as | 類(lèi)型轉(zhuǎn)換(也用作指定類(lèi)前綴)) |
| is | 如果對(duì)象是指定類(lèi)型則返回 true |
| is! | 如果對(duì)象是指定類(lèi)型則返回 false |
當(dāng)且僅當(dāng) obj對(duì)象 實(shí)現(xiàn)了 T 的接口,obj對(duì)象 is T 才是 true。例如 obj對(duì)象 is Object 總為 true,因?yàn)樗蓄?lèi)都是 Object 的子類(lèi)。
僅當(dāng)你確定這個(gè)對(duì)象是該類(lèi)型的時(shí)候,你才可以使用 as 操作符可以把對(duì)象轉(zhuǎn)換為特定的類(lèi)型。例如:
(emp as Person).firstName = 'Bob';
如果你不確定這個(gè)對(duì)象類(lèi)型是不是 T,請(qǐng)?jiān)谵D(zhuǎn)型前使用 is T 檢查類(lèi)型。
if (emp is Person) {
// 類(lèi)型檢查
emp.firstName = 'Bob';
}
你可以使用 as 運(yùn)算符進(jìn)行縮寫(xiě):
(emp as Person).firstName = 'Bob';
賦值運(yùn)算符
可以使用 = 來(lái)賦值,同時(shí)也可以使用 ??= 來(lái)為值為 null 的變量賦值。
// 將 value 賦值給 a (Assign value to a)
a = value;
// 當(dāng)且僅當(dāng) b 為 null 時(shí)才賦值
b ??= value;
像 += 這樣的賦值運(yùn)算符將算數(shù)運(yùn)算符和賦值運(yùn)算符組合在了一起。
| = | –= | /= | %= | >>= | ^= |
| += | *= | ~/= | <<= | &= | = |
下面的例子展示了如何使用賦值以及復(fù)合賦值運(yùn)算符:
a += b //就 等同于 a = a + b
var a = 2; // 使用 = 賦值 (Assign using =)
a *= 3; // 賦值并做乘法運(yùn)算 Assign and multiply: a = a * 3
assert(a == 6);
邏輯運(yùn)算符
| 類(lèi)型判斷運(yùn)算符 | 描述 |
|---|---|
| !表達(dá)式 | 對(duì)表達(dá)式結(jié)果取反(即將 true 變?yōu)?false,false 變?yōu)?true) |
| || | 邏輯或 |
| && | 邏輯與 |
下面是使用邏輯表達(dá)式的示例:
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
按位和移位運(yùn)算符
| 按位和移位運(yùn)算符 | 描述 |
|---|---|
| & | 按位與 |
| | | 按位或 |
| ^ | 按位異或 |
| ~ 表達(dá)式 | 按位取反(即將 “0” 變?yōu)?“1”,“1” 變?yōu)?“0”) |
| << | 位左移 |
| >> | 位右移 |
下面是使用按位和移位運(yùn)算符的示例:
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)
條件表達(dá)式
條件 ? 表達(dá)式 1 : 表達(dá)式 2 :如果條件為 true,執(zhí)行表達(dá)式 1并返回執(zhí)行結(jié)果,否則執(zhí)行表達(dá)式 2 并返回執(zhí)行結(jié)果。
表達(dá)式 1 ?? 表達(dá)式 2:如果表達(dá)式 1 為非 null 則返回其值,否則執(zhí)行表達(dá)式 2 并返回其值。
如果賦值是根據(jù)布爾表達(dá)式則考慮使用 ?:
var visibility = isPublic ? 'public' : 'private';
如果賦值是根據(jù)判定是否為 null 則考慮使用 ??
String playerName(String name) => name ?? 'Guest';
上述示例還可以寫(xiě)成至少下面兩種不同的形式,只是不夠簡(jiǎn)潔:
// 相對(duì)使用 ?: 運(yùn)算符來(lái)說(shuō)稍微長(zhǎng)了點(diǎn)。(Slightly longer version uses ?: operator).
String playerName(String name) => name != null ? name : 'Guest';
// 如果使用 if-else 則更長(zhǎng)。
String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
級(jí)聯(lián)運(yùn)算符
級(jí)聯(lián)運(yùn)算符(..)可以讓你在同一個(gè)對(duì)象上連續(xù)調(diào)用多個(gè)對(duì)象的變量或方法。
比如下面的代碼:
querySelector('#confirm') // 獲取對(duì)象 (Get an object).
..text = 'Confirm' // 使用對(duì)象的成員 (Use its members).
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
第一個(gè)方法 querySelector 返回了一個(gè) Selector 對(duì)象,后面的級(jí)聯(lián)操作符都是調(diào)用這個(gè) Selector 對(duì)象的成員并忽略每個(gè)操作的返回值。
上面的代碼相當(dāng)于:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
級(jí)聯(lián)運(yùn)算符可以嵌套,例如:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
在返回對(duì)象的函數(shù)中謹(jǐn)慎使用級(jí)聯(lián)操作符。例如,下面的代碼是錯(cuò)誤的:
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // 出錯(cuò):void 對(duì)象中沒(méi)有方法 write (Error: method 'write' isn't defined for 'void').
上述代碼中的 sb.write() 方法返回的是 void,返回值為 void 的方法則不能使用級(jí)聯(lián)運(yùn)算符。
其他運(yùn)算符
大多數(shù)其它的運(yùn)算符,已經(jīng)在其它的示例中使用過(guò):
| 運(yùn)算符 | 名字 | 描述 |
|---|---|---|
| () | 使用方法 | 代表調(diào)用一個(gè)方法 |
| [] | 訪問(wèn) List | 訪問(wèn) List 中特定位置的元素 |
| . | 訪問(wèn)成員 | 成員訪問(wèn)符 |
| ?. | 條件訪問(wèn)成員 | 與上述成員訪問(wèn)符類(lèi)似,但是左邊的操作對(duì)象不能為 null,例如 foo?.bar,如果 foo 為 null 則返回 null ,否則返回 bar |
更多關(guān)于 ., ?. 和 .. 運(yùn)算符介紹,會(huì)在下一章Flutter手把手教程Dart語(yǔ)言——類(lèi)中講解.