Flutter 零基础入门(十一):空安全(Null Safety)基础

Flutter&Dart零基础入门教程(一)
Flutter 零基础入门(二):Dart 字符串与字符串插值
Flutter 零基础入门(三):条件判断与逻辑运算
Flutter零基础入门(四):switch、多分支判断与循环
Flutter零基础入门(五):List列表与遍历
Flutter 零基础入门(六):Map 键值对与简单数据模型
Flutter 零基础入门(七):函数(Function)与代码封装
Flutter 零基础入门(八):Dart 类(Class)与对象(Object)
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
Flutter 零基础入门(十):final、const 与不可变数据

Flutter 零基础入门(十一):空安全(Null Safety)基础

在前面的学习中,我们已经学会了:

  • 变量与数据类型
  • List、Map、Class
  • final、const 与不可变数据

但你在实际写 Dart 代码时,很可能已经遇到过类似提示:

  • ❌ A value of type 'null' can't be assigned
  • ❌ The property 'xxx' can't be accessed because it is potentially null

这些问题,都指向同一个核心概念:

👉 空安全(Null Safety)


一、什么是 null?

null 表示:

什么都没有 / 不存在 / 未赋值

例如:

  • 用户还没登录
  • 数据还没加载
  • 接口还没返回结果

在早期语言中,null 非常容易导致运行时崩溃(空指针异常)。


二、为什么 Dart 要引入空安全?

在没有空安全的情况下:

dart 复制代码
String name;
print(name.length); // ❌ 运行时崩溃

问题是:

  • 编译时不会报错
  • 错误在运行时才出现

📌 Dart 的目标是:

尽可能在编译阶段发现问题

于是就有了 Null Safety


三、默认情况下:变量不能为 null

在空安全开启后(Flutter 默认开启):

复制代码
String name = 'Tom';
name = null; // ❌ 编译报错

结论:

默认情况下,所有变量都不允许为 null

这是 Dart 空安全的第一条核心规则。


四、可空类型:?

如果一个变量确实可能为空,你必须明确告诉 Dart。

1️⃣ 使用 ? 声明可空类型

复制代码
String? name;

含义:

  • name 可以是 String
  • 也可以是 null

2️⃣ 给可空变量赋值

复制代码
String? name = null;
name = 'Tom';

这样写是完全合法的。


五、访问可空变量的问题

来看一个常见错误:

复制代码
String? name = 'Tom';
print(name.length); // ❌ 报错

为什么?

因为:

  • Dart 不确定 name 是否为 null
  • 如果是 null,访问 .length 就会崩溃

六、解决方式一:判空(if 判断)

复制代码
if (name != null) {
  print(name.length);
}

这是最安全、最推荐的方式。

📌 原则:

先判断,再使用


七、解决方式二:!(非空断言)

复制代码
print(name!.length);

! 的含义是:

"我保证这里一定不是 null"

⚠️ 注意:

  • 如果你判断错了
  • 程序仍然会在运行时崩溃

📌 使用建议:

少用、慎用、明确场景再用


八、解决方式三:?.(安全调用)

复制代码
print(name?.length);

含义:

  • 如果 name 不为 null → 返回长度
  • 如果 name 为 null → 返回 null

这是 Dart 提供的非常优雅的写法


九、??:提供默认值

复制代码
String? name;
print(name ?? 'Guest');

含义:

  • 如果 name 为 null
  • 就使用 'Guest'

📌 在 Flutter UI 中非常常见。


十、空安全与函数参数

1️⃣ 参数默认不可为空

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

调用时:

复制代码
greet(null); // ❌ 报错

2️⃣ 可空参数写法

复制代码
void greet(String? name) {
  print('Hello ${name ?? 'Guest'}');
}

十一、空安全与类属性(非常重要)

复制代码
class User {
  final String name;
  final int age;

  User(this.name, this.age);
}

这里:

  • name、age 必须有值
  • 对象一旦创建就是"完整状态"

如果属性可能为空:

复制代码
class User {
  String? avatar;
}

📌 Dart 强制你 在设计阶段就想清楚数据是否可能为空


十二、一个综合示例

复制代码
class User {
  final String name;
  final int? age;

  User(this.name, this.age);
}

void printUser(User user) {
  print('姓名:${user.name}');
  print('年龄:${user.age ?? '未知'}');
}

这个例子体现了:

  • 可空类型
  • ?? 默认值
  • 空安全的真实用法

十三、空安全的核心思想总结

空安全不是为了让你多写符号,而是为了:

  • 提前发现问题
  • 减少运行时崩溃
  • 强迫你设计清晰的数据结构

📌 一句话理解:

Dart 不允许你"模棱两可"地使用数据


十四、总结

本篇你已经学会了:

  • 什么是 null
  • 什么是空安全
  • ?!?.?? 的含义
  • 如何在变量、函数、类中使用空安全

你已经完成了从:

"随便用数据" → "严谨使用数据" 的关键升级


🔜 下一篇预告

《Flutter 零基础入门(十二):枚举(enum)与状态管理的第一步》

下一篇我们将学习:

  • 什么是 enum
  • 为什么 enum 比 int / String 更安全
  • 用 enum 表示状态
  • 为 Flutter 页面状态打基础

从下一篇开始,我们会逐步进入:

Flutter 状态与 UI 逻辑的核心世界

相关推荐
txinyu的博客2 小时前
解析业务层的key冲突问题
开发语言·c++·分布式
码不停蹄Zzz2 小时前
C语言第1章
c语言·开发语言
行者963 小时前
Flutter与OpenHarmony跨平台分享组件深度实践
flutter·harmonyos·鸿蒙
行者963 小时前
Flutter跨平台开发在OpenHarmony上的评分组件实现与优化
开发语言·flutter·harmonyos·鸿蒙
阿蒙Amon3 小时前
C#每日面试题-Array和ArrayList的区别
java·开发语言·c#
SmartRadio3 小时前
ESP32添加修改蓝牙名称和获取蓝牙连接状态的AT命令-完整UART BLE服务功能后的完整`main.c`代码
c语言·开发语言·c++·esp32·ble
且去填词4 小时前
Go 语言的“反叛”——为什么少即是多?
开发语言·后端·面试·go
知乎的哥廷根数学学派4 小时前
基于生成对抗U-Net混合架构的隧道衬砌缺陷地质雷达数据智能反演与成像方法(以模拟信号为例,Pytorch)
开发语言·人工智能·pytorch·python·深度学习·机器学习
yeziyfx4 小时前
kotlin中 ?:的用法
android·开发语言·kotlin