目录

迁移到空安全

:::版本说明 Dart 2.19 是最终支持空安全迁移的版本,包括 dart migrate 工具。要将你的包迁移到空安全,请使用 Dart 2.19.6 SDK。更多信息,请参见 Dart 3 和空安全 。 :::

本页介绍如何以及何时将你的代码迁移到 空安全 。以下是迁移你拥有的每个包的基本步骤:

  1. 等待 你依赖的包进行迁移。
  2. 迁移 你包的代码,最好使用交互式迁移工具。
  3. 静态分析 你包的代码。
  4. 测试 以确保你的更改有效。
  5. 如果该包已发布到 pub.dev,则 发布 空安全版本作为 预发布 版本。

:::小提示 如果你的应用程序或库很大,请查看 大型 Dart 项目的逐步空安全迁移 。 :::

:::备注 从技术上讲,迁移应用与迁移包相同。 在迁移应用之前,请确保所有依赖项都已准备好。 :::

要非正式地了解使用迁移工具的体验,请观看此视频:


How to migrate Dart packages to null safety

1. 等待迁移

#

我们强烈建议按顺序迁移代码,首先迁移依赖关系图的叶子节点。例如,如果包 C 依赖于包 B,而包 B 依赖于包 A,则应首先将 A 迁移到空安全,然后是 B,最后是 C。

C/B/A 语句的图示 {:width="454px"}

尽管你 可以 迁移 到空安全之前你的依赖项支持空安全,但你的依赖项迁移时你可能需要更改你的代码。例如,如果你预测一个函数将接受一个可空参数,但该包将其迁移为不可空,那么传递可空参数将成为编译错误。

:::备注 你可以在依赖于它的包迁移之前——也应该——迁移你的包。 你的空安全包可被尚未使用空安全的包和应用使用,只要它们使用 Dart 2.12 或更高版本即可。例如,Dart 和 Flutter 核心库是空安全的,它们仍然可以被尚未迁移到空安全的应用使用。 :::

本节将说明如何在空安全模式下使用 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

如果输出表示所有包都支持空安全,那么你可以开始迁移。否则,如果存在,请使用 可解析 列查找空安全版本。

:::备注 为什么所有依赖项都需要支持空安全? 当应用程序的所有直接依赖项都支持空安全时,你可以使用健全的空安全 运行应用程序 。当所有开发依赖项都支持空安全时,你可以使用健全的空安全 运行测试 。你可能还需要空安全的开发依赖项来完成其他操作,例如代码生成。 :::

这是一个简单包的输出示例。每个包的绿色勾选版本都支持空安全:

dart pub outdated 的输出

输出显示该包的所有依赖项都具有支持空安全的可解析预发行版。

如果你的包的任何依赖项 尚未 支持空安全,我们鼓励你联系包所有者。你可以在 pub.dev 上的包页面上找到联系方式。

更新依赖项

#

在迁移包的代码之前,请将其依赖项更新到空安全版本:

  1. 运行 dart pub upgrade --null-safety 以升级到支持空安全的最新版本。 注意: 此命令会更改你的 pubspec.yaml 文件。

  2. 运行 dart pub get

2. 迁移

#

你的代码需要空安全的许多更改很容易预测。例如,如果一个变量可以为 null它的类型需要 ? 后缀 。如果命名参数不应该为空,请将其标记为 required 或赋予它 默认值

你拥有两种迁移选项:

:::小提示 迁移代码期间,如有任何其他帮助,请查看 空安全常见问题解答 。 :::

使用迁移工具

#

迁移工具获取不安全的 Dart 代码包,并将其转换为空安全。你可以通过向 Dart 代码添加 提示标记 来指导工具的转换。

在启动工具之前,请确保你已准备好:

  • 使用 Dart SDK 的 2.19.6 版本。
  • 使用 dart pub outdated --mode=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? 列表。

理解迁移结果

#

要查看每个更改(或未更改)的原因,请单击 建议的编辑 窗格中的行号。原因将显示在 编辑详细信息 窗格中。

例如,考虑以下代码,来自空安全之前的代码:

dart
var ints = const <int>[0, null];
var zero = ints[0];
var one = zero + 1;
var zeroOne = <int>[zero, one];

当此代码位于函数之外时(在函数内有所不同),默认迁移是向后兼容的,但并不理想:

dart
var ints = const <int?>[0, null];
var zero = ints[0];
var one = zero! + 1;
var zeroOne = <int?>[zero, one];

通过单击 第 3 行 链接,你可以看到迁移工具添加 ! 的原因。因为你知道 zero 不能为 null,所以你可以改进迁移结果。

改进迁移结果

#

当分析推断出错误的可空性时,你可以通过插入临时提示标记来覆盖其建议的编辑:

  • 在迁移工具的 编辑详细信息 窗格中,你可以使用添加 /*?*/ 提示 添加 /*!*/ 提示按钮插入提示标记。

    这些按钮会立即向你的文件添加注释,并且 没有撤消操作 。如果你不想要工具插入的提示,你可以使用你常用的代码编辑器将其删除。

  • 你可以使用编辑器添加提示标记,即使工具仍在运行。因为你的代码尚未启用空安全,所以你无法使用新的空安全功能。但是,你可以进行不依赖于空安全功能的更改,例如重构。

    完成代码编辑后,单击 从源代码重新运行 以获取你的更改。

下表显示你可以用来更改迁移工具建议的编辑的提示标记。

提示标记对迁移工具的影响
expression /!/向迁移后的代码添加 ! ,将 expression 转换为其底层的不可空类型。
type /!/type 标记为不可空。
/*?*/将前面的类型标记为可空。
/*late*/将变量声明标记为 late ,表示它具有延迟初始化。
/*late final*/将变量声明标记为 late final ,表示它具有延迟的、一次性初始化。
/*required*/将参数标记为 required

单个提示可能会对代码的其他地方产生连锁反应。在之前的示例中,手动在 zero 被赋值的地方(第 2 行)添加 /*!*/ 标记,会使迁移工具将 zero 的类型推断为 int 而不是 int? 。此类型更改可能会影响直接或间接使用 zero 的代码。

dart
var zero = ints[0]/*!*/;

使用上述提示,迁移工具会更改其建议的编辑,如下面的代码片段所示。第 3 行不再在 zero 之后有 ! ,并且在第 4 行中, zeroOne 被推断为 int 列表,而不是 int? 列表。

第一次迁移使用提示的迁移
dart
var ints = const <int?>[0, null];
var zero = ints[0];
var one = zero! + 1;
var zeroOne = <int?>[zero, one];
dart
var ints = const <int?>[0, null];
var zero = ints[0]/*!*/;
var one = zero + 1;
var zeroOne = <int>[zero, one];

选择退出文件

#

虽然我们建议一次性迁移所有内容,但在某些情况下,这并不实用,尤其是在大型应用或包中。要选择退出文件或目录,请单击其绿色复选框。稍后,当你应用更改时,每个选择退出的文件都将保持不变,除了 2.9 的 版本注释

有关增量迁移的更多信息,请参阅 不安全的空安全

请注意,只有完全迁移的应用程序和包才与 Dart 3 兼容。

应用更改

#

当你喜欢迁移工具建议的所有更改时,请单击 应用迁移 。迁移工具将删除提示标记并保存迁移后的代码。该工具还会更新 pubspec 中的最小 SDK 约束。

这会将包选择加入空安全。

下一步是 静态分析你的代码 。如果有效,则 测试你的代码 。然后,如果你已在 pub.dev 上发布了你的代码,则 发布空安全预发行版

手动迁移

#

如果你不想使用迁移工具,你可以手动迁移。

我们建议你 首先迁移叶子库 ——不导入包中其他文件的库。然后迁移直接依赖于叶子库的库。最后迁移具有最多包内依赖项的库。

例如,假设你有一个 lib/src/util.dart 文件,它导入其他(空安全)包和核心库,但没有任何 import '<local_path>' 指令。考虑首先迁移 util.dart ,然后迁移仅依赖于 util.dart 的简单文件。如果任何库具有循环导入(例如,A 导入 B,B 导入 C,C 导入 A),请考虑同时迁移这些库。

要手动迁移包,请按照以下步骤操作:

  1. 编辑包的 pubspec.yaml 文件,将最小 SDK 约束设置为至少 2.12.0

    yaml
    environment:
      sdk: '>=2.12.0 <3.0.0'
  2. 重新生成包配置文件

    $ dart pub get

    使用至少 2.12.0 的较低 SDK 约束运行 dart pub get 会将包中每个库的默认语言版本设置为至少 2.12,从而将它们全部选择加入空安全。

  3. 在你的 IDE 中打开该包。
    你可能会看到很多分析错误。没关系。

  4. 使用分析器识别静态错误来迁移每个 Dart 文件的代码。
    根据需要添加 ?!requiredlate 来消除静态错误。

有关手动迁移代码的更多帮助,请参阅 不安全的空安全

3. 分析

#

更新你的包(在你的 IDE 或命令行中使用 dart pub get )。然后使用你的 IDE 或命令行对你的代码执行 静态分析

$ dart pub get
$ dart analyze     # 或 `flutter analyze`

4. 测试

#

如果你的代码通过了分析,请运行测试:

$ dart test       # 或 `flutter test`

你可能需要更新预期为 null 值的测试。

如果你需要对代码进行大量更改,则可能需要重新迁移它。如果是这样,请在再次使用迁移工具之前撤消代码更改。

5. 发布

#

我们鼓励你尽快发布包(可能作为预发行版):

更新包版本

#

更新包的版本以指示重大更改:

  • 如果你的包已达到 1.0.0 或更高版本,请增加主版本号。例如,如果之前的版本是 2.3.2 ,则新版本是 3.0.0

  • 如果你的包尚未达到 1.0.0 ,则 或者 增加次要版本号 或者 将版本更新为 1.0.0 。例如,如果之前的版本是 0.3.2 ,则新版本是 0.4.01.0.0

检查你的 pubspec

#

在发布包的稳定空安全版本之前,我们强烈建议遵循以下 pubspec 规则:

  • 将 Dart 的最低 SDK 约束设置为已测试的最低稳定版本(至少为 2.12.0 )。
  • 使用所有直接依赖项的稳定版本。

欢迎来到空安全的世界

#

如果你走到这一步,你应该已经拥有一个完全迁移的、空安全的 Dart 包。

如果你的所有依赖包也都已迁移,则你的程序在空引用错误方面是健全的。运行或编译代码时,你应该看到如下输出:

Compiling with sound null safety

来自整个 Dart 团队,感谢你迁移你的代码。