美文网首页跨平台开发公交站Flutter飞起
Flutter 里的语法糖解析,知其所然方能潇洒舞剑

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

作者: 恋猫月亮 | 来源:发表于2021-07-22 16:31 被阅读0次

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

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

image

其实这个问题很简单:

  • 1、在 Dart 的 Sound Null Safety 下声明了非空的对象是不需要判空;(你想判断也行,会有警告⚠️)
  • 2、使用了 late 关键字声明的对象,如果在没有初始化的时候直接访问,就会报错;

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

late

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

image

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

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

image

typedef

介绍完 late 接下介绍下 typedeftypedef 在 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 是不参与到编译后的代码运行,所以也不会对代码的运行效率有什么影响。

image

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

image

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

image

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

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

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

image

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

extension

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

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

image

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

image image

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

image

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

image
image

async / await

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

image

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

image

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

image

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

当然,如果用不上,拿去面试“装X”其实也挺不错的不是么?

相关文章

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

    本篇主要针对 Flutter 里 Dart 的一些语法糖实现进行解析,让你明显简单声明的关键字背后,Dart 究竟...

  • 2017-10-13

    知其然,知其所以然,知其可为之然。

  • 知其所以然方能学会说话之道

    昨天我在网络上报了一个提升自我的学习班,第一节课就是教人说话的情商课。不得不说,当一个人开始进入职场,就会不自觉地...

  • 2019-08-12

    知其然知其所以然

  • 知其然 知其所以然

  • Kotlin进阶学习笔记

    Kotlin进阶学习笔记 从源码分析学习Kotlin,知其然、知其所以然。 通用基础语法学习Kotlin官网[ht...

  • 知其所以然并不容易

    大人总教育孩子“知其然也要知其所以然”,但真要孩子不停的问问什么,想知其所以然时,怕是大人也不知其所以然了。飞机为...

  • 学习编程的四个阶段

    学会 知其所然,掌握一些最基本的编程知识比如某一些语法 会学 知其以然,能够快速而深刻地理解技术,并举一反三,根据...

  • Android AsyncTask源码解析,知其所以然

    前言 AsyncTask是很多人接触的第一个用来完成异步任务的东西。相信大家都知道它的使用方法,今天我们来看一下他...

  • 2018-07-13求真

    知其然,还知其所以然。

网友评论

    本文标题:Flutter 里的语法糖解析,知其所然方能潇洒舞剑

    本文链接:https://www.haomeiwen.com/subject/lgfymltx.html