Flutter 在 Dart 3.8 开始支持 Null-Aware Elements 语法,自动识别集合里的空元素

近日,在 Dart 3.8 的 changelog 里正式提交了 Null-Aware Elements 语法,该语法糖可以用于在 List、Set、Map 等集合中处理可能为 null 的元素或键值对,简化显式检查 null 的场景:

js 复制代码
/////////////////之前
var listWithoutNullAwareElements = [
  if (promotableNullableValue != null) promotableNullableValue,
  if (nullable.value != null) nullable.value!,
  if (nullable.value case var value?) value,
];
​
/////////////////之后
var listWithNullAwareElements = [
  ?promotableNullableValue,
  ?nullable.value,
  ?nullable.value,
];

自然,在 Flutter 的 UI 声明里,也可以简化之前控件的 if 判断,不得不说确实比起之前的写法优雅不少:

js 复制代码
/////////////////之前
Stack(
  fit: StackFit.expand,
  children: [
    const AbsorbPointer(),
    if (widget.child != null) widget.child!,
  ],
)
​
/////////////////之后
Stack(
  fit: StackFit.expand,
  children: [
    const AbsorbPointer(),
    ?widget.child,
  ],
)

同时,官方在分析了大量开源 Dart 代码后(90019 个文件中的 17,941,439 行代码),发现这类需要支持的场景更多是 Map

js 复制代码
-- Surrounding collection (1812 total) --
   1566 ( 86.424%): Map   ===============================================
    241 ( 13.300%): List  ========
      5 (  0.276%): Set   =

而事实上,从以下例子可以看出来,在简化 Map 上 Null-Aware Elements 的作用尤为明显:

js 复制代码
/////////////////之前
final tag = Tag()
  ..tags = {
    if (Song.title != null) 'title': Song.title,
    if (Song.artist != null) 'artist': Song.artist,
    if (Song.album != null) 'album': Song.album,
    if (Song.year != null) 'year': Song.year.toString(),
    if (comments != null)
      'comment': comms!
          .asMap()
          .map((key, value) => MapEntry<String, Comment>(value.key, value)),
    if (Song.numberInAlbum != null) 'track': Song.numberInAlbum.toString(),
    if (Song.genre != null) 'genre': Song.genre,
    if (Song.albumArt != null) 'picture': {pic.key: pic},
  }
  ..type = 'ID3'
  ..version = '2.4';
​
/////////////////之后
final tag = Tag()
  ..tags = {
    'title': ?Song.title,
    'artist': ?Song.artist,
    'album': ?Song.album,
    'year': ?Song.year?.toString(),
    if (comments != null)
      'comment': comms!
          .asMap()
          .map((key, value) => MapEntry<String, Comment>(value.key, value)),
    'track': ?Song.numberInAlbum?.toString(),
    'genre': ?Song.genre,
    if (Song.albumArt != null) 'picture': {pic.key: pic},
  }
  ..type = 'ID3'
  ..version = '2.4';

通过下面的简单例子,也可以看出来有了 Null-Aware Elements 之后在代码简化效果上很明显:

当然,配合其他语法也能达到去 null 的效果,比如最简单的 for 循环,通过 ?i ,就可以简单到做排除空数据的目的:

当然,你可能会觉得本来 Dart 里就有很多 ? ,比如 ?? 、 ?. 之类,加上语法之后会不会有歧义?这个问题在目前的规则上看起来还行,例如此时的 ? 前通常是 ,[{ : 等符号,这些上下文和现有 ? 用法不同 :

js 复制代码
var list = [1, ?foo]; // ? 是空感知元素,不是其他用法
var map = {key: ?value}; // ? 是空感知值,不是可空类型

并且前面介绍过,与现有语法如 iffor 元素结合时,? 出现在 if for 头部后也不会有歧义:

js 复制代码
var list = [
  for (var i in [1, 2]) ?i, // 合法:?i 是空感知元素
];
print(list); // 输出: [1, 2]

而在 Flutter 里的 UI 编排了就更加直观了:

当然,这个语法还是有一些规则限制,在这个规则下 expression 只能是一个普通表达式,不能是另一个集合,比如嵌套的 ? 或展开操作 ...

js 复制代码
element ::=
  | nullAwareExpressionElement
  | nullAwareMapElement
  | // Existing productions...
​
nullAwareExpressionElement ::= '?' expression
​
nullAwareMapElement ::=
  | '?' expression ':' '?'? expression // Null-aware key or both.
  |     expression ':' '?' expression  // Null-aware value.

例如下方代码就可以很直观展示这个错误使用,同时也没有 ????foo?if (c) nullableThing else otherNullableThing 这样的场景:

可以看到, Null-aware elements 语法不管是在逻辑代码还是 UI 代码都十分有用,虽然 Dart 3.8 还没正式发布,但是你可以在 Flutter beta channel 提前体验,那么,你觉这个语法符合你的审美吗?

参考链接

相关推荐
霸王蟹27 分钟前
React中useState中更新是同步的还是异步的?
前端·javascript·笔记·学习·react.js·前端框架
霸王蟹30 分钟前
React Hooks 必须在组件最顶层调用的原因解析
前端·javascript·笔记·学习·react.js
专注VB编程开发20年37 分钟前
asp.net IHttpHandler 对分块传输编码的支持,IIs web服务器后端技术
服务器·前端·asp.net
爱分享的程序员1 小时前
全栈项目搭建指南:Nuxt.js + Node.js + MongoDB
前端
编程乐学(Arfan开发工程师)2 小时前
06、基础入门-SpringBoot-依赖管理特性
android·spring boot·后端
隐含2 小时前
webpack打包,把png,jpg等文件按照在src目录结构下的存储方式打包出来。解决同一命名的图片资源在打包之后,重复命名的图片就剩下一个图片了。
前端·webpack·node.js
androidwork2 小时前
使用 Kotlin 和 Jetpack Compose 开发 Wear OS 应用的完整指南
android·kotlin
lightYouUp2 小时前
windows系统中下载好node无法使用npm
前端·npm·node.js
Dontla2 小时前
npm cross-env工具包介绍(跨平台环境变量设置工具)
前端·npm·node.js
小妖6662 小时前
vue2 切换主题色以及单页面好使方法
前端·vue.js·elementui