本文原作者: 恋猫de小郭,原文发布于: GSYTech

本篇主要针对 Flutter 里 Dart 的一些语法糖实现进行解析,让您明白简单声明的关键字背后,Dart 究竟做了什么?

如下图所示,起因是在群里看到一个很基础的问题,问: "这段代码为什么不能对 user 进行判空?"。

其实这个问题很简单:

  1. 在 Dart 的 Sound Null Safety 下声明了非空的对象是不需要判空;(您想判断也行,会有警告⚠️)

  2. 使用了 late 关键字声明的对象,如果在没有初始化的时候直接访问,就会报错;

所以这个问题其实很简单,只需要改成 User? user 就可以简单解决,但是为什么本来不可以为空的对象,加了 late 就可以不马上初始化呢?

late

首先如下图所示,我们写一段简单的代码,通过 late 声明了一个 playerAnimation 对象,然后在运行代码之后,通过 dump_kernel.dart 对编译后的 app.dill 进行提取。

如下图所示,通过提取编译后的代码,可以看到 playerAnimation 其实被转变成了 Animation? 的可空对象,而当 playerAnimation 被调用时,通过 get playerAnimation() 进行判断,如果此时 playerAnimation == null,直接就抛出 LateError 错误。

所以当我们访问 late 声明的对象时,如果对象还没有初始化,就会返回一个异常。

typedef

介绍完 late 接下来介绍一下 typedef,typedef 在 Dart 2.13 开始可以用于新的类型别名功能,比如:

// Type alias for functions (existing)
typedef ValueChanged<T> = void Function(T value);// Type alias for classes (new!)
typedef StringList = List<String>;// Rename classes in a non-breaking way (new!)
@Deprecated("Use NewClassName instead")
typedef OldClassName<T> = NewClassName<T>;

那么 typedef 是如何工作的?如下图所示,可以看到 _getDeviceInfo 方法在编译后,其实直接就被替换为 List<String>,所以实际上 StringList 是不参与到编译后的代码运行,所以也不会对代码的运行效率有什么影响。

再举个例子,如下图所示,可以看到通过 SelectItemChanged 声明的 selectItemChanged,在编译后其实直接就是 final field (dynamic) →? void selectItemChanged; 。

接着我们通过 Dart 的 tear-off 来看另外一个现象,如下图所示,可以看到我们从一个任意对象中 x 中提取了 toString 方法,通过闭包,就可以像调用常规实例一样调用 x。

如果在一个对象上调用函数并省略了括号,Dart 称之为 "tear-off": 一个和函数使用同样参数的闭包,当调用闭包的时候会执行其中的函数,比如: names.forEach(print); 等同于 names.forEach((name){print(name);});

那么编译后的 getToString 方法会是怎么样的?

如下图所示,可以看到 getToString 方法在编译后成了一个 static 的静态方法,并且 ToStringFn 也没有实际参与运行,也是被替换成了对应的 ()-> core:String。

所以对于编译后的代码,typedef 并不会对性能和运行结果产生影响。

extension

在 Dart 里,通过 extension 可以很便捷地为对象进行拓展,那 extension 关键字是如何在原对象基础上实现拓展呢?

如下图所示,我们声明了一个 Cat 的枚举,并且对 Cat 进行了拓展,从而为枚举的每个值赋值,并且加了 talk 方法。

如下图所示,编译后 Cat 里的枚举值对应变成了一个 static final 的固定地址,并且 CatExtension 里的 talk 和 value 也被指向了新的位置。

找到对应的实现处发现,CatExtension 里的 name 和 talk 都变了所在文件下的 static method,并且 talk 方法是先定义了 method 实现,之后再通过 tearoff 的 get 实现去调用,基本上所有在 extension 里定义的方法都会有对应的 method 和 tearoff

如下图所示,在 Cat 的使用处,编译后可以看到 cat.talk() 其实就是执行了 main::CatExtension|talk。

async / await

最后聊聊 async / await,我们都知道这是 Dart 里 Future 的语法糖,那这个语法糖在编译后是如何运行的呢?

可以看到,loadmore 方法在编译后被添加了很多的代码,其中定义了一个 _Future<void> async_future 并在最后返回,同时我们需要执行的代码被包装到 async_op 里去执行,而这里有一个很关键的地方就是,async_op 对执行的内容进行了 try catch 的操作,并通过 _completeOnAsyncError 返回

这也是为什么我们在外部对一个 Future 进行 try catch 不能捕获异常的原因,所以如下图所示,对于 Future 需要通过 .onError((error, stackTrace) => null) 的方式来对异常进行捕获处理。

明白了这些关键字背后的实现后,相信可以更好地帮助您在 Flutter 的日常开发中更优雅地组织您的代码,从而避免很多不需要的问题。


长按右侧二维码

查看更多开发者精彩分享

"开发者说·DTalk" 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE) 的推荐。

 点击屏末 |  | 即刻报名参与 "开发者说·DTalk"


Flutter 里的语法糖解析,知其所然方能潇洒舞剑 | 开发者说·DTalk相关推荐

  1. Flutter 里的语法糖解析,知其所然方能潇洒舞剑

    本篇主要针对 Flutter 里 Dart 的一些语法糖实现进行解析,让你明显简单声明的关键字背后,Dart 究竟做了什么? 如下图所示,起因是昨天在群里看到一个很基础的问题,问: "这段代 ...

  2. Flutter 里的语法糖解析,知其所然方能潇洒舞剑,安卓开发面试题及答案

    介绍完 late 接下介绍下 typedef, typedef 在 Dart 2.13 开始可以用于**「新的类型别名功能」**,比如: // Type alias for functions (ex ...

  3. Flutter 里的语法糖解析,知其所然方能潇洒舞剑,为什么阿里的程序员成长如此之快

    ================================================================ 首先如下图所示,我们写一段简单的代码,通过 late 声明了一个 pl ...

  4. Flutter 里的语法糖解析,知其所然方能潇洒舞剑,10天用Flutter撸了个高仿携程App

    如下图所示,「起因是昨天在群里看到一个很基础的问题」,问: "这段代码为什么不能对 user 进行判空?" . 其实这个问题很简单: 1.在 Dart 的 **「Sound Nul ...

  5. switch(String)语法糖解析

    switch(String)语法糖解析 Java1.5之前,switch语法结构仅支持int, byte, short, char这几个基本类型(及对应的包装类型). 1.5后提供了enum枚举结构. ...

  6. 什么是语法糖(Syntactic sugar)?

    大学时没选修编译原理这门课,不知道什么是语法糖,最近看React的官方文档才接触语法糖的概念,简单查了下资料记录下,以下是来自百度百科的解释: 语法糖(Syntactic sugar),也译为糖衣语法 ...

  7. 【JAVA SE】第十四章 集合框架、语法糖和泛型

    第十四章 集合框架.语法糖和泛型 文章目录 第十四章 集合框架.语法糖和泛型 一.集合框架 1.概念 2.接口 二.语法糖 1.概念 2.解语法糖 三.泛型 1.概念 2.泛型类 3.泛型接口 4.泛 ...

  8. python数列求和-加强版_ES6深入浅出-3 三个点运算 新版字符串-1.函数与对象的语法糖...

    主要讲的内容 时间充裕的话就讲,模板字面量 默认参数值 首先讲es6之前,我们是怎么做的.例如我们要写一个求和的函数, 请两个参数的和,但是如果有的人就是穿一个参数呢? 那么b没有传值,b的值是多少呢 ...

  9. 2020国庆节 Angular structual 指令学习笔记(<ng-template>) 包含语法糖解糖过程

    Structural directives are responsible for HTML layout. They shape or reshape the DOM's structure, ty ...

最新文章

  1. oracle为什么不用指定数据库,两个数据库怎么保持数据正确显示
  2. PreparedStatement
  3. linux mint 下载辅助工具,Linux Mint 18.2 下载工具AxeluGet
  4. 阿里P8亲自教你!熬夜整理华为最新Java笔试题
  5. “算法”的茧房,如何破局?
  6. 期刊检索级别简单介绍
  7. 扫雷php,扫雷php
  8. C++实现CS模型(计算机网络)
  9. Android 端音频变声方案
  10. 软考真题的重要性不用再强调了吧
  11. 我记得你往日的样子----聂鲁达
  12. Flex布局子元素对齐方式
  13. 什么是浮点型?什么是单精度浮点数(float)以及双精度浮点数(double)?
  14. About Spreadsheets
  15. ETFE膜和PTFE膜不同之处以及特点-世来福
  16. props的基本使用和特点
  17. 在各种裁员的“寒冬”,还应该对年终奖有多少期待?!
  18. java共享锁和排他锁的区别_排他锁和共享锁分别是什么?有什么不同?
  19. oracle clear buffer,Out 对象的 clearBuffer() 方法用来清除缓冲区里的数据,但并不把数据写到客户端。...
  20. supermap地图风格优化

热门文章

  1. 暑期社会实践总结报告
  2. 技校学生计算机周记,周记大全技校
  3. Unity 屏幕特效后期处理 OnRenderImage
  4. css_复合选择器_border_css层叠性与覆盖性_background_多标记构图法_行高_文本修饰属性_超链接的伪类_导航制作_Unit_4;
  5. tensorfow/model下object_detection训练错误记录
  6. CVPR 2022 | Adobe把GAN搞成了缝合怪!凭空P出一张1024分辨率全身人像
  7. 【原创】终结选择困难,Xshell、MobaXterm、PuTTY、SecureCRT 多款 SSH 终端软件该怎么选
  8. 一文读懂有关Tree的前世今生
  9. 海康监控主机无法登录后台解决办法
  10. linux怎么找网卡驱动,linux系统下如何安装网卡驱动