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) ...
算数操作符
基本使用:
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); // 求余
Dart还支持前置和后置增量和减量运算符:
var a, b;
a = 0;
b = ++a; // 赋值前自增
assert(a == b); // 1 == 1
a = 0;
b = a++; // 赋值后自增
assert(a != b); // 1 != 0
a = 0;
b = --a; // 赋值前自减
assert(a == b); // -1 == -1
a = 0;
b = a--; // 复制后自减
assert(a != b); // -1 != 0
等于和相关操作符
要测试两个objectx和y是否表示相同的事物,请使用==运算符。(在极少数情况下,你需要知道两个对象是否完全相同,请使用 identical()函数来代替。)以下是==运算符的工作原理:
- 如果两个都为
null,返回true,如果只有一个为null返回false。 - 返回调用
x.==(y)的结果。(没错,运算符如==是在第一个操作数上调用的方法。前面提到了,你可以覆盖许多运算符,包括==,具体使用在介绍Dart中的类时会介绍,详情:Overridable operators。)。
典型示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
类型测试操作符
as,is和is!运算符在运行时检查类型很方便。obj is T的结果取决于obj是否实现了T的接口,我们知道Dart中都是object,所以obj is Object总是返回true。(is!的用法和is相反)
当我们不确定某个变量是不是实现了某个类的接口时,需要判断一下,然后再使用:
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
as操作符可以所写这个判断:
(emp as Person).firstName = 'Bob';
这两种写法不完全相同。如果**emp**为**null**或不是**Person**,则第一个示例(用 **is**)不执行任何操作;第二个(用**as**)抛出一个异常。
赋值操作符
也就是给变量赋值的操作符(=):
// 赋值给变量a
a = value;
// 只有当b为空时才赋值给b,否则保持b的值不变。
b ??= value;
赋值运算符,把赋值和运算操作整合到一起,以下是常见的赋值运算符:
= |
–= |
/= |
%= |
>>= |
^= |
|---|---|---|---|---|---|
+= |
*= |
~/= |
<<= |
&= |
|= |
var a = 2; // 普通的赋值
a *= 3; // 等价于 a = a * 3
assert(a == 6);
逻辑运算符
可以使用逻辑运算符反转或组合布尔表达式:
| 操作符 | 含义 |
|---|---|
!_expr_ |
反转bool值 |
|| |
逻辑或 |
&& |
逻辑与 |
例子:
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
位操作符
你可以在Dart中操纵数字的二进制位。通常,您将使用对整数使用这些操作符:
final value = 5; // 二进制的101 前面的0这里省略显示了
final bitmask = 3; // 二进制的011 前面的0这里省略显示了
// 按位与,都是1返回1,其它返回0
print(value & bitmask); // 二进制的001 也就是1
// 按位或,只要有一个1返回1,都是0返回0
print(value | bitmask); // 二进制的111 也就是7
由于位操作符不太常用,其它用法大家可以自行查找,这里不在赘述。
条件表达式
三元表达式:
// isPublic为true,返回public,反之返回private
var visibility = isPublic ? 'public' : 'private';
简单的判断是否为空值(null):
// 传入的name不为空时返回name,没有传入返回'Guest';
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';
}
}
级联操作符
Cascades(..)允许你对同一对象进行一系列操作。除了函数调用,还可以访问同一对象上的字段。这可以省略穿件临时变量,也让代码更好看:
// 这里的两个操作和一个取值赋值,都在querySelector('#confirm')上面操作
// 级联操作符会忽略每一个子句的返回值。
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
// 等价于
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() // 这里的PhoneNumberBuilder()在number和label赋值后,返回给phone
..number = '415-555-0100'// 返回给phone的是PhoneNumberBuilder()
..label = 'home')
.build())
.build();
注意使用级联操作符时,一定要对一个实际的object上执行:
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // Error: method 'write' isn't defined for 'void'.
// sb.write('foo')返回的是void。你不能在void上面使用级联操作符
其他常用的操作符
| 操作符 | 说明 |
|---|---|
() |
执行方法 |
[] |
list的索引访问 |
. |
表达式的属性访问 例如: foo.bar 从 foo取 bar |
?. |
类似 ., 但是左边的表达式为空时不会报错,而是返回空。例子: foo?.bar 从 foo取 bar ,如果foo为null,那么foo?.bar 返回空。 |