每日一题 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 站 。

相关推荐
键盘歌唱家12 分钟前
mysql索引失效
android·数据库·mysql
野盒子43 分钟前
前端面试题 微信小程序兼容性问题与组件适配策略
前端·javascript·面试·微信小程序·小程序·cocoa
王中阳Go1 小时前
2025Java面试八股②(含121道面试题和答案)
java·后端·面试
webbin1 小时前
Compose @Immutable注解
android·android jetpack
汪子熙2 小时前
QRCode.js:一款轻量级、跨浏览器的 JavaScript 二维码生成库
前端·javascript·面试
小小神仙2 小时前
JSCommon系列 - 前端常用工具库集合
前端·javascript·面试
无知的前端2 小时前
Flutter开发,GetX框架路由相关详细示例
android·flutter·ios
玲小珑2 小时前
Auto.js 入门指南(十二)网络请求与数据交互
android·前端
webbin2 小时前
Compose 副作用
android·android jetpack
知其然亦知其所以然2 小时前
只会写 Mapper 就想进大厂?MyBatis 原理你真懂了吗?
java·后端·面试