每日一题 Flutter#10 | Dart 空安全六君子


最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 Flutter 为核心,准备题库资源。于是诞生《每日一题》 系列,准备精心设计一些 Flutter 的问题与解答,作为题库的养料。本文的焦点是探讨:

Dart 语法中,和 ? 符号相关的空安全符号

在 Dart 的语法体系中,?! 是空安全机制的核心操作符。它们组成了空安全六君子:?, ?., ??, ??=, ...?, !,每一个都肩负不同职责,共同守护程序的空值安全。

- -
!

1.空安全操作符六君子

空安全是 Dart 非常重要的一个特性,在语法层面,围绕空安全有 6 个操作符号,它们各自承担着防崩溃、判断空、赋默认值、保证非空等职责,是写出健壮 Dart/Flutter 代码的必修课。本题就将它们一网打尽,聊聊其具体含义

  • Type?:可空类型标记
  • ?.:空安全成员访问
  • ??:空值合并操作符
  • ??=:空值赋值操作符
  • ...?: 空安全展开操作符
  • ! : 非空断言操作符

2.空类型声明 Type?

这是 Dart 空安全特性的核心之一,用于声明一个 可以为 null 的变量

dart 复制代码
String? name = null;
int? age = 18;

如果 greet 入参是声明 String? 类型,就意味着该变量可能是 null,你就必须在使用前判断或处理它的可能为空。

dart 复制代码
void greet(String? name) {
  if (name != null) {
    print("Hello, $name");
  }
}

如果 greet 入参是 String 类型,就意味着该变量永远不为 null。在当前的方法作用域内,可以保证 name 的非空性,可以安全使用。

dart 复制代码
void greet(String name) {
  print("Hello, $name");
}

3.空安全成员访问 ?.

这个符号的作用是:仅当对象不为 null 时才调用成员 。若对象为 null,则整个表达式返回 null,不会抛出异常

dart 复制代码
class User {
  String? nickname;
}

void main() {
  User? user = null;

  // 不会抛出异常,返回 null
  print(user?.nickname);
}

这极大地简化了原本的 if 判断写法:

dart 复制代码
if (user != null) {
  print(user.nickname);
}

4.空值合并操作符 ??

这个符号用于判断一个表达式是否为 null,如果是,就使用后面的默认值。

dart 复制代码
String? name = null;
print(name ?? "default"); // 输出 default

也可以结合函数返回值使用:

dart 复制代码
String? getName() => null;

void main() {
  String displayName = getName() ?? "匿名";
  print(displayName); // 匿名
}

5.空值赋值操作符 ??=

如果变量当前是 null,就赋值为指定值:

dart 复制代码
String? name;
name ??= "张三";
print(name); // 张三

等价于:

dart 复制代码
if (name == null) {
  name = "张三";
}

6.空安全展开操作符 ...?

这个在上一篇的 . 相关符号中介绍过。用于在集合中展开一个可能为 null 的列表或集合。当值为 null 时,它将忽略这一部分,不会抛出异常。

dart 复制代码
List<int>? nums = null;
List<int> result = [0, ...?nums, 1];
// => [0, 1]

如果没有 ...? 而使用 ...,则会抛出运行时异常:

dart 复制代码
List<int>? nums = null;
List<int> result = [0, ...nums]; // ❌ 报错

7.非空断言操作符 !

! 是 Dart 中一个"强势"的操作符,它的意思是:

我,开发者亲口保证这个值一定不为 null。

如果你错了,程序会崩溃。

dart 复制代码
String? name;
print(name!); // ❌ 如果 name 是 null,会抛出异常

典型场景:有时我们逻辑上能确保变量不为 null,但编译器无法判断:

dart 复制代码
String? getName() => "Tom";

void main() {
  String name = getName()!; // 告诉 Dart: "我确定"
}

使用 ! 时建议加注释说明原因,防止团队踩坑。如果你不百分之百确诊一个可空对象在当前运行时非空,千万别加 !

dart 复制代码
String name = valueFromApi!; // 我确认 API 永远返回非空

8. 小结

同样空安全的符号六君子,这里也给一首打油诗:

空值安全六君子,声明赋值各显威,

Type? 表可空,?. 出手防崩溃。

?? 给默认值,??= 为空能赋值。

...? 展开很谨慎,空集来了也无畏,

若敢拍胸 ! 保证,空了看我把你锤!

操作符 名称 作用说明
Type? 可空类型标记 声明变量可以为 null
?. 空安全成员访问 对象为 null,不调用,返回 null
?? 空值合并操作符 若左边为 null,使用右边默认值
??= 空值赋值操作符 若变量为 null,则赋予新值
...? 空安全展开操作符 展开可空集合,null 不展开
! 非空断言操作符 告诉编译器值绝不为空,否则崩溃

如果你有其他的看法,或者有什么想要的题目、或者想提供题目和答案,都欢迎在评论区留言。更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
xiangzhihong81 小时前
使用Universal Links与Android App Links实现网页无缝跳转至应用
android·ios
车载应用猿2 小时前
基于Android14的CarService 启动流程分析
android
天涯学馆2 小时前
网站秒变 App!手把手教你搞定 PWA
前端·javascript·面试
没有了遇见3 小时前
Android 渐变色实现总结
android
UrbanJazzerati3 小时前
使用 Thunder Client 调用 Salesforce API 的完整指南
面试·visual studio code
bo521003 小时前
浏览器渲染机制详解(包含渲染流程、树结构、异步js)
前端·面试·浏览器
呆呆的心3 小时前
大厂面试官都在问的 WEUI Uploader,源码里藏了多少干货?🤔
前端·微信·面试
雨白5 小时前
Jetpack系列(四):精通WorkManager,让后台任务不再失控
android·android jetpack
Codebee6 小时前
如何利用OneCode注解驱动,快速训练一个私有的AI代码助手
前端·后端·面试
一个 00 后的码农6 小时前
26考研物理复试面试常见问答问题汇总(2)电磁波高频面试问题,物理专业保研推免夏令营面试问题汇总
考研·面试·职场和发展