此文是致力于帮助你更好地理解并高效使用 Dart 语言系列文集的第一篇。
Dart(2.0+) 和 Flutter 都是相对较新的技术,每天都有大量的人加入开发者社区,他们参考的很多示例代码仍在照搬其他语言中的代码模式,而未使用 Dart 提供的完整运算符集。
1、 ?:(三目运算符)
三目运算符已经存在于许多语言中,它允许将 if-else
语句中两条可能的执行路径改写为更简洁的形式。
比如以下代码:
可以写成:
三元运算符的结构如下所示:
condition ? (statement if true) : (statement if false);
如果涉及到返回值,return
只需要加在开头,而不是在子语句中:
return condition ? (statement if true) : (statement if false);
而不是
condition ? return (statement if true) : return (statement if false);
2、 ??
??
是 null 检查符。在上例中,如果 person.name
为 null,则 name
被赋值为 "John Doe"。这大大简化了代码,减少了先检查 name 是否为空,再决定如何赋值的逻辑(如下图的代码对比)。
??
运算符无需大量检查代码,能更加容易地处理意外的 null 值。
3、?.
设想一个叫 Point
的类,它有 x 和 y 成员:
classPoint {
int x;
int y;
Point(this.x, this.y);
}
如果我们有一个未初始化的 Point 对象,并且试图访问内部成员,它不会返回 null,而是直接抛出一个错误。
比如:
Point point;
print(point.x);
将抛出:
Unhandled exception:
NoSuchMethodError: The getter 'x'was called on null.
Receiver: null
Tried calling: x
相反,如果它只返回 null,我们可以就很容易地处理和解决未初始化的问题。
同样,简单的解决方案是使用 if-else:
这看起来不错,但很容易遇到限制。以我们解析 JSON 为例,它可能有很多层嵌套的数据。比如:
pages[0].contributors[0].authorDetails.basicInfo.firstName
程序中任何错误都可能导致这个调用链中某个部分为 null。例如说,authorDetails
可能根本没有 basicInfo
字段。
在这些情况下,判空检查是一场噩梦,只要这些字段中的一个字段为空(firstName
除外,因为它是最后一个字段),则整个调用都会失败。
那我们该怎么办?没有简单的 if-else 或三目运算解决方案。而且在一个完美的系统里,这个错误根本不应该存在,但我们并不总会有完美的系统和 API。此时,?.
运算符派上用场了。
这个运算符大致表述为:“如果对象不为 null,则访问内部字段,否则返回 null。”
因此,即使我们前面的 point.x
示例也会抛出 null 而不是错误。这使我们的工作变得更加容易,并且可以简单地使用上一个运算符来处理 null 错误。
这里如果 point 未初始化,访问 x 将返回 null 而不是抛出错误。然后这个 null 被 null 检查运算符(??)捕获,该运算符将 0 赋值给变量 x。
类似地,我们可以将前面的示例修改为:
pages[0]?.contributors[0]?.authorDetails?.basicInfo?.firstName ?? "N/A";
现在,如果表达式任意部分为 null,则将返回 "N/A"。
4、??=
??=
可简单的理解为:“如果表达式左侧为空,则执行赋值”。即只有当变量为 null 时才会被赋值。
可以避免给变量做不必要的重新赋值。
5、=>
=>
在 Dart 中被称为胖箭头 (fat arrow) 符号。它有两种不同的用途,两者都与定义函数有关。
首先将其作为返回某物的简写,=> x
表示 { return x;}
此外该运算符也适用于单个语句,即使不返回任何内容。
请注意,如果返回类型是 void,则即使是 => s
也不会返回任何东西。
6、..(级联符号)
级联表示法是一种修改对象属性的简单方式,通常用于在创建对象而不是获取该对象的引用时逐个修改其属性。
我们要举的第一个例子还是之前的 Point
类。假设我们首先需要初始化类,然后设置x和y属性。你可能会想到这么做:
Point p = Point();
p.x= 3;
p.y= 6;
级联表示法为我们提供了一种更简单的方法,无需再次使用对象来设置属性。
需要注意的,如果我们只是使用 .
运算符,第一行不会返回一个 Point
对象。
级联符号的主要作用是:
1. 将 Point
对象创建为默认值;
2. 通过级联操作更改任何受影响的属性;
3. 返回原始对象(此处为 Point
实例);
这在需要设置大量属性时非常有用,例如在 Builder 模式中。Dart 文档中有个很好的例子:
7、~/
Dart 也有几个用于加速算术运算的运算符。~/
运算符返回除法计算结果的整数部分。
以上介绍的这些运算符简化了代码并减少了 Bug 的发生。
8、追加:展开运算符 ...(尚未发布)
...
是一个还在讨论中的运算符,用作 Dart 中集合 (collections) 的展开运算符。
List 可以很方便地被展开:
这段代码直接将 demoList
的元素展开添加至列表中,而不是将其作为 List 对象添加。
来源:https://medium.com/flutter-community/simple-and-bug-free-code-with-dart-operators-2e81211cecfe
作者:Deven Joshi
编译:码王爷