善用 Dart 运算符编写简洁无错的代码

善用 Dart 运算符编写简洁无错的代码_第1张图片

此文是致力于帮助你更好地理解并高效使用 Dart 语言系列文集的第一篇。

Dart(2.0+) 和 Flutter 都是相对较新的技术,每天都有大量的人加入开发者社区,他们参考的很多示例代码仍在照搬其他语言中的代码模式,而未使用 Dart 提供的完整运算符集。

1、 ?:(三目运算符)

三目运算符已经存在于许多语言中,它允许将 if-else 语句中两条可能的执行路径改写为更简洁的形式。

比如以下代码:

善用 Dart 运算符编写简洁无错的代码_第2张图片

可以写成:

善用 Dart 运算符编写简洁无错的代码_第3张图片

三元运算符的结构如下所示:

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、 ??

善用 Dart 运算符编写简洁无错的代码_第4张图片

?? 是 null 检查符。在上例中,如果 person.name 为 null,则 name 被赋值为 "John Doe"。这大大简化了代码,减少了先检查 name 是否为空,再决定如何赋值的逻辑(如下图的代码对比)。

善用 Dart 运算符编写简洁无错的代码_第5张图片

?? 运算符无需大量检查代码,能更加容易地处理意外的 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:

善用 Dart 运算符编写简洁无错的代码_第6张图片

这看起来不错,但很容易遇到限制。以我们解析 JSON 为例,它可能有很多层嵌套的数据。比如:

pages[0].contributors[0].authorDetails.basicInfo.firstName

程序中任何错误都可能导致这个调用链中某个部分为 null。例如说,authorDetails 可能根本没有 basicInfo 字段。

在这些情况下,判空检查是一场噩梦,只要这些字段中的一个字段为空(firstName 除外,因为它是最后一个字段),则整个调用都会失败。

那我们该怎么办?没有简单的 if-else 或三目运算解决方案。而且在一个完美的系统里,这个错误根本不应该存在,但我们并不总会有完美的系统和 API。此时,?. 运算符派上用场了。

这个运算符大致表述为:“如果对象不为 null,则访问内部字段,否则返回 null。”

因此,即使我们前面的 point.x 示例也会抛出 null 而不是错误。这使我们的工作变得更加容易,并且可以简单地使用上一个运算符来处理 null 错误。

善用 Dart 运算符编写简洁无错的代码_第7张图片

这里如果 point 未初始化,访问 x 将返回 null 而不是抛出错误。然后这个 null 被 null 检查运算符(??)捕获,该运算符将 0 赋值给变量 x。

类似地,我们可以将前面的示例修改为:

pages[0]?.contributors[0]?.authorDetails?.basicInfo?.firstName ?? "N/A";

现在,如果表达式任意部分为 null,则将返回 "N/A"。

4、??=

??= 可简单的理解为:“如果表达式左侧为空,则执行赋值”。即只有当变量为 null 时才会被赋值。

善用 Dart 运算符编写简洁无错的代码_第8张图片

可以避免给变量做不必要的重新赋值。

5、=>

=> 在 Dart 中被称为胖箭头 (fat arrow) 符号。它有两种不同的用途,两者都与定义函数有关。

首先将其作为返回某物的简写,=> x 表示 { return x;}

善用 Dart 运算符编写简洁无错的代码_第9张图片

此外该运算符也适用于单个语句,即使不返回任何内容。

善用 Dart 运算符编写简洁无错的代码_第10张图片

请注意,如果返回类型是 void,则即使是 => s 也不会返回任何东西。

6、..(级联符号)

级联表示法是一种修改对象属性的简单方式,通常用于在创建对象而不是获取该对象的引用时逐个修改其属性。

我们要举的第一个例子还是之前的 Point 类。假设我们首先需要初始化类,然后设置x和y属性。你可能会想到这么做:

Point p = Point();
p.x= 3;
p.y= 6;

级联表示法为我们提供了一种更简单的方法,无需再次使用对象来设置属性。

善用 Dart 运算符编写简洁无错的代码_第11张图片

需要注意的,如果我们只是使用 . 运算符,第一行不会返回一个 Point 对象。

级联符号的主要作用是:

1. 将 Point 对象创建为默认值;

2. 通过级联操作更改任何受影响的属性;

3. 返回原始对象(此处为 Point 实例);

这在需要设置大量属性时非常有用,例如在 Builder 模式中。Dart 文档中有个很好的例子:

善用 Dart 运算符编写简洁无错的代码_第12张图片

7、~/

Dart 也有几个用于加速算术运算的运算符。~/ 运算符返回除法计算结果的整数部分。

善用 Dart 运算符编写简洁无错的代码_第13张图片

以上介绍的这些运算符简化了代码并减少了 Bug 的发生。

8、追加:展开运算符 ...(尚未发布)

... 是一个还在讨论中的运算符,用作 Dart 中集合 (collections) 的展开运算符。

List 可以很方便地被展开:

善用 Dart 运算符编写简洁无错的代码_第14张图片

这段代码直接将 demoList 的元素展开添加至列表中,而不是将其作为 List 对象添加。


来源:https://medium.com/flutter-community/simple-and-bug-free-code-with-dart-operators-2e81211cecfe
作者:Deven Joshi
编译:码王爷

你可能感兴趣的:(善用 Dart 运算符编写简洁无错的代码)