
最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 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 站 。