Dart 运算符

2023/5/16

# Dart 运算符

一旦你使用了运算符,就创建了表达式。下面是一些运算符表达式的示例:

a++
a + b
a = b
a == b
c ? a : b
a is T
1
2
3
4
5
6

# 算数运算符

算术运算符基本与 JavaScript 保持一致,但是多了一个 除并取整运算符:~/

assert(5 ~/ 2 == 2)
1

# 关系运算符

关系运算符基本与 JavaScript 保持一致。

要判断两个对象 x 和 y 是否表示相同的事物使用 == 即可。(在极少数情况下,可能需要 identical() 函数来确定两个对象是否完全相同)。下面是 == 运算符的一些规则:

  1. 当 x 和 y 同时为空时返回 true,而只有一个为空时返回 false。
  2. 返回一个函数调用的结果:x.==(y)。(这个调用是正确的,像 == 这样的运算符实际上是由 第一个操作数所调用的一个方法)。你可以重写大部分运算符。

# 类型判断运算符

as、is、is! 运算符是在运行时判断对象类型的运算符。

  • as 类型转换
  • is 如果对象是指定类型则返回 true
  • is! 如果对象是指定类型则返回 false

当且仅当 obj 实现了 T 的接口,Obj is T 才是 true。例如 Obj is Object 总为 true,因为所有类都是 Object 的子类。仅当你确定这个对象是该类型的时候,你才可以使用 as 操作符可以把对象转换为特定的类型。例如:

(employee as Person).firstName = 'Bob';
1

如果你不确定这个对象类型是不是 T,请在转型前使用 is T 检查类型。

if (employee is Person) {
    employee.firstName = 'Bob';
}
1
2
3

上述两种方式是有区别的:如果 employee 为 null 或者不为 Person 类型,则第一种方式将会抛出异常,而第二种不会。

# 赋值运算符

可以使用 = 来赋值,同时也可以使用 ??= 来为值为 null 的变量赋值。

a = value;

// 如果 b 为 null,则给 b 赋值;否则,b 保持不变
b ??= value;
1
2
3
4

# 逻辑运算符

使用逻辑运算符你可以反转或组合布尔表达式。

  • !表达式 对表达式结果取反(即将 true 变为 false,false 变为 true)
  • || 逻辑或
  • && 逻辑与

下面是使用逻辑表达式的示例:

if (!done && (col == 0 || col == 3)) {
  // ...Do something...
}
1
2
3

# 条件表达式

Dart 有两个特殊的运算符可以用来替代 if-else 语句:

条件 ? 表达式1 : 表达式2
1

如果条件为 true,执行表达式 1 并返回执行结果,否则执行表达式 2 并返回执行结果。

表达式 1 ?? 表达式 2
1

如果表达式 1 为非 null 则返回其值,否则执行表达式 2 并返回其值。

根据布尔表达式确定赋值时,请考虑使用 ? 和 :

var visibility = isPublic ? 'public' : 'private';
1

如果赋值是根据判定是否为 null 则考虑使用 ?? :

String playerName(String? name) => name ?? 'Guest';
1

# 级联运算符

级联运算符(..,?..)可以让你在同一个对象上连续调用多个对象的变量或方法。 比如下面的代码:

var paint = Paint()
    ..color = Colors.black
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 5.0;
1
2
3
4

级联运算符允许您对同一对象执行一系列操作。除了函数调用,您还可以访问同一对象上的字段。这通常会省去创建临时变量的步骤,并允许您编写更多的级联代码。

上面的示例可以等同于下面的代码:

var paint = Paint();
paint.color = Colors.black
paint.strokeCap = StrokeCap.round
paint.strokeWidth = 5.0;
1
2
3
4

如果级联操作的对象可以为 null,那么第一次操作使用 ?.. 级联运算符,以 ?.. 开头可以保证不会对该空对象尝试任何级联操作。

上面的代码相当于:

var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();
1
2
3
4
5

在返回对象的函数中谨慎使用级联操作符。例如,下面的代码是错误的:

var sb = StringBuffer();
sb.write('foo')
    ..write('bar'); // Error: method 'write' isn't defined for 'void'.
1
2
3

上述代码中的 sb.write() 方法返回的是 void,返回值为 void 的方法则不能使用级联运算符

# 其他运算符

  • () 代表调用一个方法
  • [] 访问 List 中特定位置的元素
  • ?[] 左侧调用者不为空时,访问 List 中特定位置的元素
  • . 成员访问符
  • ?. 与上述成员访问符类似,但是左边的操作对象不能为 null,例如 foo?.bar,如果 foo 为 null 则返回 null,否则返回 bar
  • ! 将表达式的类型转换为其基础类型,如果转换失败会抛出运行时异常。例如 foo!.bar,如果 foo 为 null,则抛出运行时异常