dart 如何优雅的避空 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
AndroidTraveler
V2EX    程序员

dart 如何优雅的避空

  •  
  •   AndroidTraveler 2019-02-23 17:32:21 +08:00 2796 次点击
    这是一个创建于 2490 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

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

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

    本篇通过对比一般非空判断和 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 的语法糖很优雅,一行全搞定。

    5. print 方法遇到 null

    下面这个例子:

    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

    6 条回复    2019-02-25 16:19:43 +08:00
    lxmfly123
        1
    lxmfly123  
       2019-02-24 11:33:14 +08:00
    发错地方了吧!
    AndroidTraveler
        2
    AndroidTraveler  
    OP
       2019-02-24 21:05:51 +08:00
    @lxmfly123 没有吧。没有 Flutter 模块。又不算前端。跟程序员有关,就发到这里了
    lxmfly123
        3
    lxmfly123  
       2019-02-25 09:34:37 +08:00
    这篇文章的内容应该发在公众号里 ,而不是这种讨论板块。

    截了一张 程序员 板块目前最新主题的截图,https://imgchr.com/i/k5lgF1,感受一下。
    lxmfly123
        4
    lxmfly123  
       2019-02-25 09:36:13 +08:00
    链接和文字粘一起了,凑合着感受吧。
    AndroidTraveler
        5
    AndroidTraveler  
    OP
       2019-02-25 10:28:17 +08:00
    @lxmfly123 个人公众号也有发。发到这里是为了让更多人看到吧。看到一个 Blog 版块,后面在那边发发。可能最终系列博客总结会在这里发下。
    lxmfly123
        6
    lxmfly123  
       2019-02-25 16:19:43 +08:00
    发现你的“吧”字比“的”字用得还多~~~
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1165 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 17:50 PVG 01:50 LAX 09:50 JFK 12:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86