迁移到 null safety
本页介绍如何以及何时将代码迁移到 null safety。以下是迁移你拥有的每个包的基本步骤
- 等待你依赖的包完成迁移。
- 迁移你的包代码,最好使用交互式迁移工具。
- 静态分析你的包代码。
- 测试以确保你的更改有效。
- 如果包已在 pub.dev 上,则以预发布 (prerelease) 版本发布支持 null safety 的版本。
要非正式地了解使用迁移工具的体验,请观看此视频
1. 等待迁移
#我们强烈建议按顺序迁移代码,首先迁移依赖关系图的叶子节点。例如,如果包 C 依赖于包 B,而包 B 依赖于包 A,那么应首先将 A 迁移到 null safety,然后是 B,最后是 C。

尽管你可以在依赖项支持 null safety 之前进行迁移,但当你的依赖项迁移时,你可能需要更改代码。例如,如果你预测函数将接受一个可空参数,但包将其迁移为不可空,那么传递一个可空参数就会成为编译错误。
本节介绍如何借助 null safety 模式下的 dart pub outdated 命令检查和更新包的依赖项。说明假定你的代码处于版本控制之下,以便你可以轻松撤销任何更改。
切换到 Dart 2.19.6 版本
#切换到 Dart SDK 的 2.19.6 版本。此版本包含在 Flutter 3.7.12 SDK 中。
检查你是否安装了 Dart 2.19.6
dart --version
Dart SDK version: 2.19.6检查依赖状态
#使用以下命令获取包依赖项的迁移状态
dart pub outdated --mode=null-safety如果输出显示所有包都支持 null safety,那么你就可以开始迁移了。否则,请使用Resolvable列查找支持 null safety 的版本(如果存在)。
以下是简单包的输出示例。每个包的绿色勾选版本都支持 null safety

输出显示,该包的所有依赖项都有可解析的、支持 null safety 的预发布版本。
如果你的包的任何依赖项尚未支持 null safety,我们鼓励你联系包所有者。你可以在 pub.dev 上的包页面上找到联系方式。
更新依赖项
#在迁移你的包代码之前,将其依赖项更新到支持 null safety 的版本
运行
dart pub upgrade --null-safety将依赖项升级到支持 null safety 的最新版本。注意:此命令会更改你的pubspec.yaml文件。运行
dart pub get。
2. 迁移
#你的代码实现 null safety 所需的大多数更改都很容易预测。例如,如果变量可以为 null,其类型需要添加 ? 后缀。如果命名参数不应可空,请将其标记为 required 或为其指定默认值。
你有两种迁移选项
使用迁移工具
#迁移工具接收一个不支持 null safety 的 Dart 代码包,并将其转换为支持 null safety 的代码。你可以通过在 Dart 代码中添加提示标记来指导工具的转换。
在启动工具之前,确保你已准备就绪
- 使用 Dart SDK 的 2.19.6 版本。
- 使用
dart pub outdated --mode=null-safety确保所有依赖项都支持 null safety 并已更新到最新版本。
通过在包含包的 pubspec.yaml 文件的目录中运行 dart migrate 命令来启动迁移工具
dart migrate如果你的包已准备好迁移,工具会生成如下所示的一行
View the migration suggestions by visiting:
http://127.0.0.1:60278/Users/you/project/mypkg.console-simple?authToken=Xfz0jvpyeMI%3D在 Chrome 浏览器中访问该 URL,查看交互式 UI,你可以在其中指导迁移过程

对于每个变量和类型注解,你可以看到工具推断的可空性。例如,在上面的屏幕截图中,工具推断第 1 行的 ints 列表(以前是 int 列表)是可空的,因此应该是一个 int? 列表。
理解迁移结果
#要查看每个更改(或非更改)的原因,请在Proposed Edits面板中单击其行号。原因会显示在Edit Details面板中。
例如,考虑以下代码,这是在 null safety 之前编写的
var ints = const <int>[0, null];
var zero = ints[0];
var one = zero + 1;
var zeroOne = <int>[zero, one];当此代码位于函数外部时(在函数内部不同),默认的迁移方式向后兼容,但并非理想
var ints = const <int?>[0, null];
var zero = ints[0];
var one = zero! + 1;
var zeroOne = <int?>[zero, one];通过单击第 3 行链接,你可以看到迁移工具添加 ! 的原因。因为你知道 zero 不可能为 null,所以你可以改进迁移结果。
改进迁移结果
#当分析推断出错误的可空性时,你可以通过插入临时提示标记来覆盖其建议的更改
在迁移工具的Edit Details面板中,你可以使用Add
/*?*/hint和Add/*!*/hint按钮插入提示标记。这些按钮会立即将注释添加到你的文件中,并且无法撤消。如果你不想要工具插入的提示,可以使用常用的代码编辑器将其删除。
你可以使用编辑器添加提示标记,即使工具仍在运行。由于你的代码尚未选择加入 null safety,因此无法使用新的 null safety 特性。但是,你可以进行不依赖于 null safety 特性的更改,例如重构。
完成代码编辑后,单击Rerun from sources以加载你的更改。
下表显示了你可以用来更改迁移工具建议的编辑的提示标记。
| 提示标记 | 对迁移工具的影响 |
|---|---|
表达式 /!/ | 在迁移后的代码中添加 !,将表达式强制转换为其底层不可空类型。 |
类型 /!/ | 将类型标记为不可空。 |
/*?*/ | 将前面的类型标记为可空。 |
/*late*/ | 将变量声明标记为 late,表示它具有延迟初始化。 |
/*late final*/ | 将变量声明标记为 late final,表示它具有延迟的、一次性初始化。 |
/*required*/ | 将参数标记为 required。 |
一个提示可能会在代码的其他地方产生连锁反应。在前面的示例中,手动在为 zero 赋值的位置(第 2 行)添加 /*!*/ 标记,会使迁移工具将 zero 的类型推断为 int,而不是 int?。这种类型更改可能会影响直接或间接使用 zero 的代码。
var zero = ints[0]/*!*/;有了上述提示,迁移工具会改变其建议的编辑,如下面的代码片段所示。第 3 行 zero 后面不再有 !,第 4 行 zeroOne 被推断为 int 列表,而不是 int? 列表。
| 首次迁移 | 带有提示的迁移 |
|---|---|
dart | dart |
退出文件
#虽然我们建议一次性迁移所有代码,但有时这并不实际,尤其是在大型应用或包中。要退出一个文件或目录,请单击其绿色的复选框。稍后,当你应用更改时,每个退出文件除了 2.9 版本注释外,将保持不变。
有关增量迁移的更多信息,请参阅 不健全的 null safety。
请注意,只有完全迁移的应用和包才与 Dart 3 兼容。
应用更改
#当你对迁移工具建议的所有更改都满意时,点击Apply migration。迁移工具会删除提示标记并保存迁移后的代码。工具还会更新 pubspec 文件中的最低 SDK 约束,这会将包选择加入 null safety。
下一步是静态分析你的代码。如果代码有效,然后测试你的代码。然后,如果你已在 pub.dev 上发布了代码,则发布一个支持 null safety 的预发布版本。
手动迁移
#如果你不想使用迁移工具,可以手动迁移。
我们建议你首先迁移叶子库——不导入包中其他文件的库。然后迁移直接依赖于叶子库的库。最后迁移具有最多包内依赖项的库。
例如,假设你有一个 lib/src/util.dart 文件,它导入了其他(支持 null safety 的)包和核心库,但没有任何 import '<local_path>' 指令。考虑首先迁移 util.dart,然后迁移仅依赖于 util.dart 的简单文件。如果任何库有循环导入(例如,A 导入 B,B 导入 C,而 C 导入 A),考虑将这些库一起迁移。
要手动迁移包,请按照以下步骤操作
编辑包的
pubspec.yaml文件,将最低 SDK 约束设置为至少2.12.0yamlenvironment: sdk: '>=2.12.0 <3.0.0'重新生成包配置文件
dart pub get运行
dart pub get并将最低 SDK 约束设置为至少2.12.0会将包中每个库的默认语言版本设置为最低 2.12,从而使它们全部选择加入 null safety。在你的 IDE 中打开包。
你可能会看到许多分析错误。没关系。使用分析器识别静态错误,迁移每个 Dart 文件的代码。
通过根据需要添加?、!、required和late来消除静态错误。
有关手动迁移代码的更多帮助,请参阅 不健全的 null safety。
3. 分析
#更新你的包(在 IDE 或命令行中使用 dart pub get)。然后使用你的 IDE 或命令行对你的代码执行静态分析
dart pub get
dart analyze # or `flutter analyze`4. 测试
#如果你的代码通过了分析,则运行测试
dart test # or `flutter test`你可能需要更新期望 null 值的测试。
如果你需要对代码进行较大更改,可能需要重新迁移。如果是这样,请在使用迁移工具之前恢复你的代码更改。
5. 发布
#我们鼓励你在迁移完成后尽快发布包——可能作为预发布版本
- 设置包版本以指示重大变更。
- 更新 SDK 约束和包依赖项。
- 发布包。如果你不认为此版本是稳定版本,则将包发布为预发布版本。
- 更新示例和文档
更新包版本
#更新包版本以指示重大变更
如果你的包版本已达到
1.0.0或更高,则增加主版本号。例如,如果先前版本是2.3.2,新版本则是3.0.0。如果你的包尚未达到
1.0.0,则可以增加次版本号或者将版本更新为1.0.0。例如,如果先前版本是0.3.2,新版本可以是0.4.0或1.0.0。
检查你的 pubspec 文件
#在发布包的稳定 null safety 版本之前,我们强烈建议遵循这些 pubspec 规则
- 将 Dart 的最低 SDK 约束设置为你已测试过的最低稳定版本(至少
2.12.0)。 - 使用所有直接依赖项的稳定版本。
更新示例和文档
#如果你尚未这样做,请更新包的所有示例和样本,使其使用已迁移版本的包并选择加入 null safety。
如果你为你的包发布了任何单独的文档或教程,也请确保它们已更新到支持 null safety 的版本。
null safety 欢迎你
#如果你已经完成了这些步骤,你应该拥有一个完全迁移、支持 null safety 的 Dart 包。
如果你依赖的所有包也已迁移,那么你的程序在 null 引用错误方面是健全的。在运行或编译代码时,你应该会看到类似如下的输出
Compiling with sound null safetyDart 团队全体成员衷心感谢你迁移你的代码。