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 提前体验,那么,你觉这个语法符合你的审美吗?

参考链接

相关推荐
代码老中医4 分钟前
Node_modules 比黑洞还重,我们的硬盘到底做错了什么?
前端
兆子龙4 分钟前
Vue 3 响应式系统 Reactivity 源码深度解析:从 ref 到 effect 的完整链路
前端
Smoothcloud_润云7 分钟前
GORM 事务管理与 Repository 模式完整指南
前端·数据库·代码规范
兆子龙7 分钟前
Turborepo 与 Monorepo 任务调度源码解析:从 DAG 到增量构建
前端·架构
煤球王子8 分钟前
学习记录:Android14中的Wifi_Direct(P2P)
android
兆子龙10 分钟前
React 18 并发与 Reconciler 源码解析:Fiber、调度器与可中断渲染
前端
找藉口是失败者的习惯13 分钟前
【Android】Android 车机 + AI Agent 有没有搞头?
android·人工智能
张一凡9314 分钟前
easy-model 领域驱动实践
前端·react.js
我命由我1234515 分钟前
Element Plus - Cascader 观察记录(基本使用、动态加载、动态加载下的异常环境)
开发语言·前端·javascript·vue.js·typescript·html5·js
陈林梓16 分钟前
ESLint + Prettier + Husky + lint-staged + Commitlint 的完整配置
前端