Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

dart 如何优雅的避空

AndroidTraveler 2019-02-23 15:54:00 阅读数:212 评论数:0 点赞数:0 收藏数:0

前言

对于每一个程序员来说,空指针异常应该是基本都会遇到过的异常,而且这个异常出现的概率还比较大。

但是,空指针异常又是最容易解决的异常,因为只要加个非空判断就可以避免了。

本篇通过对比一般非空判断和 dart 特有的语法糖告诉你如何使用 dart 进行优雅的避空。

目录

1. dart 在线编辑器

一般一些简单的 dart 测试我们可以直接用在线编辑器来做测试和验证。

下面给大家介绍的两个都是官网的。

dart 在线运行器主页版:
https://www.dartlang.org/guides/get-started

dart 在线运行器全屏版:
https://dartpad.dartlang.org/null

其中全屏版就是在主页版里面点击全屏按钮就打开了。

所以可以认为是一样的。

但是笔者使用起来的不同如下,大家可以根据自己的感受选择。

主页版:
优点:运行输出结果较全屏版快。
缺点:输出结果区域较小,超出需要滑动查看。

全屏版:
优点:输出结果区域大。可以直观看到结果。
缺点:运行输出结果较主页版慢。

2. dart ?.

dart 语法糖 ?.

它的意思是左边如果为空返回 null,否则返回右边的值。

A?.B
如果 A 等于 null,那么 A?.B 为 null
如果 A 不等于 null,那么 A?.B 等价于 A.B

Sample:

void main() {
Animal animal = new Animal('cat');
Animal empty = null;
//animal 非空,返回 animal.name 的值 cat
print(animal?.name);
//empty 为空,返回 null
print(empty?.name);
//animal 非空,可以直接访问 animal.name 的值 cat
print(animal.name);
//empty 为空,抛出异常
print(empty.name);
}
class Animal {
final String name;
Animal(this.name);
}

大家拷贝代码然后替换在线编辑器的内容,运行后会看到如下输出:

cat
null
cat
Uncaught exception:
Cannot read property 'get$name' of null

可以看到假设左边不为空,不管是使用?.还是直接用我们熟悉的.访问变量都是没问题的。
但是如果左边为空,使用?.会返回null。但是直接使用.会直接抛出异常。

3. dart ??

dart 语法糖 ??

它的意思是左边如果为空返回右边的值,否则不处理。

A??B
如果 A 等于 null,那么 A??B 为 B
如果 A 不等于 null,那么 A??B 为 A

以上面为例子,假设我们上面要求当 empty 为空时,默认值输出 unknown。

那么可以修改如下:

//empty 为空,返回 null
print(empty?.name);

改为

//empty 为空,本来要返回 null,由于有 ??,返回 unknown
print(empty?.name??'unknown');

这样就不会返回 null 而是返回 unknown。

同样的大家可以试下返回 cat 的语句如果加上这个会怎样,可以预见是不会改变的。

4. dart ?. ?? 优雅所在

这边举例说明下使用 ?. ?? 语法糖和不使用的对比。

void main() {
C c = new C('Case 1');
B b = new B(c);
A a = new A(b);
// C c = new C(null);
// B b = new B(c);
// A a = new A(b);
// C c = new C('Case 2');
// B b = null;
// A a = new A(b);
//直接使用.来最终获取 c 的变量 value
if (a != null && a.bMember != null && a.bMember.cMember != null) {
print(a.bMember.cMember.value);
} else {
print(null);
}
//直接使用.来最终获取 c 的变量 value,为空时返回 unknown
if (a != null && a.bMember != null && a.bMember.cMember != null) {
String value = a.bMember.cMember.value;
if (value == null) {
value = 'unknown';
}
print(value);
} else {
print('unknown');
}
//dart 使用?.来最终获取 c 的变量 value
print(a?.bMember?.cMember?.value);
//dart 使用?.来最终获取 c 的变量 value,为空时使用 ?? 返回 unknown
print(a?.bMember?.cMember?.value??'unknown');
}
class A {
final B bMember;
A(this.bMember);
}
class B {
final C cMember;
B(this.cMember);
}
class C {
final String value;
C(this.value);
}

这里面有三个 case,另外两个 case 暂时注释掉。

这三个 case 的结果分别为:

Case 1
Case 1
Case 1
Case 1
null
unknown
null
unknown
null
unknown
null
unknown

可以看到 dart 的语法糖很优雅,一行全搞定。

下面这个例子:

void main() {
String a = null;
print('exception='+a);
}

你觉得结果是 exception=null 吗?

结果是

Uncaught exception:
Invalid argument: null

原因是因为 print 里面连接的必须是字符串。

因为这里 a 确实是字符串,所以编辑器没有报错。

假设这里 a 为一个对象 A 的变量,会报如下提示:

The argument type 'A' can't be assigned to the parameter type 'String'.

那我们怎么处理?

有两种方法。

方法一:

void main() {
String a = null;
print('exception='+'$a');
}

方法二:

void main() {
String a = null??'null';
print('exception='+a);
}

注意下面的写法是不行的,原因是 ?? 优先级没有 + 高。需要加小括号。

void main() {
String a = null;
print('exception='+a??'null');
}

6. 牛刀小试

知识学以致用才能够巩固。

因此这边出了小题目给大家测试是否完全掌握本篇内容。

答案组成了支付宝口令红包哦~

微信公众号回复「牛刀小试」获取题目。

或者直接点击菜单栏目录->牛刀小试获取。

温馨提示:
如果你输入 3 次还是提示错误(错误过多口令红包会暂时不可用哦),有两种情况。

第一种就是答案错了。

第二种就是领取完了。

答案会在红包领取完之后或一天之后将题目替换为题目+答案。

因为是异步的,所以不一定实时更新哦~

更多阅读:
Flutter 即学即用系列博客——01 环境搭建
Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
Flutter 即学即用系列博客——04 Flutter UI 初窥
Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget

版权声明
本文为[AndroidTraveler]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/nesger/p/10422954.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领