内容

迁移到空安全性

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

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

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

1. 等待迁移

#

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

Illustration of C/B/A sentence

虽然您 可以 在依赖项支持空安全之前进行迁移,但当依赖项迁移时,您可能必须更改您的代码。例如,如果您预测某个函数将采用可空参数,但软件包将其迁移为不可空,那么传递可空参数将成为编译错误。

本部分告诉您如何在空安全模式下使用 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

如果输出显示所有软件包都支持空安全,则可以开始迁移。否则,使用可解决列查找空安全版本(如果存在)。

以下是简单软件包的输出示例。每个软件包的绿色对勾版本支持空安全

Output of 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,您可以在其中指导迁移过程

Screenshot of migration tool

对于每个变量和类型注释,您都可以看到该工具推断出的可空性。例如,在前面的屏幕截图中,该工具推断出第 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,所以您可以改善迁移结果。

改善迁移结果

#

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

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

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

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

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

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

提示标记对迁移工具的影响
表达式 /!/向已迁移代码添加 !,将 表达式强制转换为其基础非空类型。
类型 /!/类型 标记为非空。
/*?*/将前一个类型标记为空。
/*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 文件,它导入其他(null 安全)包和核心库,但没有任何 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,从而让它们全部选择加入 null 安全。

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

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

请参阅 不健全的 null 安全,以获取有关手动迁移代码的更多帮助。

3. 分析

#

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

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

4. 测试

#

如果您的代码通过分析,请运行测试

$ dart test       # or `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 团队,感谢您迁移您的代码。