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

参考链接

相关推荐
鹏程十八少18 小时前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
亿元程序员18 小时前
这款值68亿的游戏,你不实战一下吗?安排!
前端
Kapaseker18 小时前
一杯美式搞定 Kotlin 空安全
android·kotlin
摸鱼的春哥18 小时前
Agent教程15:认识LangChain(中),状态机思维
前端·javascript·后端
三少爷的鞋18 小时前
Android 协程时代,Handler 应该退休了吗?
android
明月_清风19 小时前
告别遮挡:用 scroll-padding 实现优雅的锚点跳转
前端·javascript
明月_清风19 小时前
原生 JS 侧边栏缩放:从 DOM 监听到底层优化
前端·javascript
万少1 天前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站1 天前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
火柴就是我1 天前
让我们实现一个更好看的内部阴影按钮
android·flutter