Dart定义了下表中显示的操作符。您可以重写其中的许多操作符,如可重写操作符中所述
| 描述 | 运算符 | ||
|---|---|---|---|
| 一元后缀 | 表达式++ 表达式-- () [] . ?. | ||
| 一元前缀 | -表达式 !表达式 ~表达式 ++表达式 --表达式 | ||
| 乘除法 | * / % ~/ | ||
| 加减法 | + - | ||
| 位运算 | << >> >>> | ||
| 二进制与 | & | ||
| 二进制异或 | |||
| 二进制或 | |||
| 关系和类型测试 | > < >= <= as is is! | ||
| 相等判断 | == != | ||
| 逻辑与 | && | ||
| 逻辑或 | |||
| 空判断 | ?? | ||
| 条件表达式 | 表达式1 ? 表达式2 : 表达式3 | ||
| expr1 ?? expr2 | |||
| 级联 | .. | ||
| 赋值 | = += -= *= /= %= ~/= >>= <<= &= ^= ??= 等等…… | ||
| 请注意:上述运算符优先级是对 Dart 解析器行为的效仿。更准确的描述,请参阅 Dart 语言规范 中的语法 |
一旦你使用了运算符,就创建了表达式。下面是一些运算符表达式的示例:
a++
a + b
a = b
a == b
c ? a : b
a is T
在运算符表 中,运算符的优先级按先后排列
- 即第一行优先级最高,最后一行优先级最低
- 而同一行中,最左边的优先级最高,最右边的优先级最低
- 括号()可以提高可读性
例如:% 运算符优先级高于 == ,而 == 高于 &&。根据优先级规则,那么意味着以下两行代码执行的效果相同:
// 括号提高了可读性。
// Parentheses improve readability.
if ((n % i == 0) && (d % i == 0)) ...
// 难以理解,但是与上面的代码效果一样。
if (n % i == 0 && d % i == 0) ...
⚠️**注意: **对于有两个操作数的运算符,左边的操作数决定了运算符的功能。比如如果有一个 Vector 对象和一个 Point 对象,表达式 aVector + aPoint 中所使用的是 Vector 对象中定义的 + 运算符
算术运算符
Dart 支持常用的算术运算符
| 运算符 | 描述 | 例子 |
|---|---|---|
| + | 加 | |
| - | 减 | |
| * | 乘 | |
| / | 除 | |
| % | 取模 | |
| -表达式 | 一元负, 也可以作为反转(反转表达式的符号) | |
| ~/ | 除并取整 | |
| ++var var++ | 递加,分为前加和后加 | var = var + 1 (表达式的值为 var + 1) |
| var = var + 1 (表达式的值为 var) | ||
| --var var-- | 递减,分为前递减和后递减 | var = var – 1 (表达式的值为 var – 1) |
| var = var – 1 (表达式的值为 var) |
main(List<String> args) {
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 结果是一个浮点数
assert(5 ~/ 2 == 2); // 结果是一个整数
assert(5 % 2 == 1); // 取余
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
var i = 0, j = 0; j = ++i; // 在 j 赋值前将 i 增加 1
print('i=${i} j=${j}'); //i=1 j=1
assert(i == j);
i = 0; j = i++; // 在 j 赋值后将 i 增加 1
print('i=${i} j=${j}'); //i=1 j=0
assert(j == i); // 0 != 1
var x = 0, y = 0;
print('++x=${++x} 加完后再输出x=${x}'); //++x=1 加完后再输出x=1
print('y++=${y++} 加完后再输出y=${y}'); //y++=0 加完后再输出y=1
var a = 0, b = 0;
print('--a=${--a} 加完后再输出a=${a}'); //--a=-1 加完后再输出a=-1
print('b--=${b--} 加完后再输出b=${b}'); //b--=0 加完后再输出b=-1
}
赋值运算符
可以使用 = 来赋值,同时也可以使用 ??= 来为值为 null 的变量赋值
a = value; // 将 value 赋值给 a (Assign value to a)
b ??= value; // 当且仅当 b 为 null 时才赋值
像这样的赋值运算符将算数运算符和赋值运算符组合在了一起
| = | += | -= | *= | /= | %= | ~/= | |
|---|---|---|---|---|---|---|---|
| ??= | &= | = | ^= | >>= | <<= |
下表解释了符合运算符的原理:
| 场景 | 复合运算 | 等效表达式 |
|---|---|---|
| 假设有运算符 op: | a op= b | a = a op b |
| 示例: | a += b | a = a + b |
下面的例子展示了如何使用赋值以及复合赋值运算符:
var a = 2; // 使用 = 赋值 (Assign using =)
a *= 3; // 赋值并做乘法运算 Assign and multiply: a = a * 3
assert(a == 6);
关系运算符
下表列出了关系运算符及含义
| 运算符 | 描述 |
|---|---|
| == | 相等 |
| != | 不等 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
要判断两个对象 x 和 y 是否表示相同的事物使用 == 即可。(在极少数情况下,可能需要使用 identical() 函数来确定两个对象是否完全相同。)。下面是 == 运算符的一些规则:
- 假设有变量 x 和 y,且 x 和 y 至少有一个为 null,则当且仅当 x 和 y 均为 null 时 x == y 才会返回 true,否则只有一个为 null 则返回 false
- x.==(y) 将会返回值,这里不管有没有 y,即 y 是可选的。也就是说 == 其实是 x 中的一个方法,并且可以被重写。详情请查阅重写运算符
下面的代码给出了每一种关系运算符的示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
逻辑运算符
使用逻辑运算符你可以反转或组合布尔表达式
| 运算符 | 描述 | ||
|---|---|---|---|
| && | 逻辑与 | ||
| 逻辑或 | |||
| !表达式 | 取非 | ||
| 对表达式结果取反(即将 true 变为 false,false 变为 true) |
下面是使用逻辑表达式的示例:
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
按位和移位运算符
在 Dart 中,二进制位运算符可以操作二进制的某一位,但仅适用于整数
| 运算符 | 描述 | |
|---|---|---|
| & | 按位与 | |
| 按位或 | ||
| 按位异或 | ||
| << | 位左移 | |
| >> | 位右移 | |
| ~表达式 | 按位取反(即将 “0” 变为 “1”,“1” 变为 “0”) |
下面是使用按位和移位运算符的示例:
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)
条件运算符
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量
| 运算符 | 描述 | |
|---|---|---|
| ? : | 条件表达式 | condition ? expr1 : expr2 |
| ?? | 空判断 | expr1 ?? expr2 |
条件表达式 Dart 有两个特殊的运算符可以用来替代 if-else 语句, 这两个运算符可以看作是特殊的关系比较符:
如果条件为真,则计算expr1(并返回其值);否则,计算并返回expr2的值
condition ? expr1 : expr2
var visibility = isPublic ? 'public' : 'private';
如果expr1是非空null的,则返回其值; 否则,计算并返回expr2的值
expr1 ?? expr2
String playerName(String name) => name ?? 'Guest';
上述示例还可以写成至少下面两种不同的形式,只是不够简洁:
// 相对使用 ?: 运算符来说稍微长了点。(Slightly longer version uses ?: operator).
String playerName(String name) => name != null ? name : 'Guest';
// 如果使用 if-else 则更长
String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
类型判断运算符
as、is、is! 运算符是在运行时判断对象类型的运算符
| 运算符 | 描述 |
|---|---|
| as | 类型转换(也用作指定类前缀)) |
| is | 如果对象是指定类型则返回 true |
| is! | 如果对象是指定类型则返回 false |
当且仅当 obj 实现了 T 的接口,obj is T 才是 true, 例如 obj is Object 总为 true,因为所有类都是 Object 的子类
仅当你确定这个对象是该类型的时候,你才可以使用 as 操作符可以把对象转换为特定的类型。例如:
(emp as Person).firstName = 'Bob';
如果你不确定这个对象类型是不是 T,请在转型前使用 is T 检查类型。
if (emp is Person) {
// 类型检查
emp.firstName = 'Bob';
}
你可以使用 as 运算符进行缩写:
(emp as Person).firstName = 'Bob';
⚠️备忘: 上述两种方式是有区别的:如果 emp 为 null 或者不为 Person 类型,则第一种方式将会抛出异常,而第二种不会
级联运算符(..)
级联运算符(..)可以让你在同一个对象上连续调用多个对象的变量或方法 比如下面的代码:
querySelector('#confirm') // 获取对象 (Get an object).
..text = 'Confirm' // 使用对象的成员 (Use its members).
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
- 第一个方法 querySelector 返回了一个 Selector 对象
- 后面的级联操作符都是调用这个 Selector 对象的成员并忽略每个操作的返回值
上面的代码相当于:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
级联运算符可以嵌套,例如:
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'); // 出错:void 对象中没有方法 write (Error: method 'write' isn't defined for 'void').
上述代码中的 sb.write() 方法返回的是 void,返回值为 void 的方法则不能使用级联运算符 ⚠️备忘: 严格来说 .. 级联操作并非一个运算符而是 Dart 的特殊语法
其他运算符
大多数其它的运算符,已经在其它的示例中使用过:
| 运算符 | 名字 | 描述 |
|---|---|---|
| () | 使用方法 | 代表调用一个方法 |
| [] | 访问 List | 访问 List 中特定位置的元素 |
| . | 访问成员 | 成员访问符 |
| ?. | 条件访问成员 | 与上述成员访问符类似,但是左边的操作对象不能为 null,例如 foo?.bar,如果 foo 为 null 则返回 null ,否则返回 bar |
更多关于 . ?. 和 .. 运算符介绍,请参考类