目录

不健全的空安全

一个 Dart 程序可能包含一些 空安全 的库和一些非空安全的库。这些 混合版本程序 依赖于 不健全的空安全

混合 语言版本 的能力使包维护者可以迁移他们的代码,并且知道即使是遗留用户也可以获得新的错误修复和其他改进。但是,混合版本程序无法获得空安全带来的所有优势。

本页描述了健全空安全和不健全空安全之间的区别,目的是帮助您决定何时迁移到空安全。概念讨论之后是增量迁移的说明,然后是关于测试和运行混合版本程序的详细信息。

健全空安全和不健全空安全

#

Dart 通过静态检查和运行时检查相结合来提供健全的空安全。每个选择加入空安全的 Dart 库都获得所有 静态 检查,以及更严格的编译时错误。即使在包含非空安全库的混合版本程序中也是如此。一旦您开始将部分代码迁移到空安全,您就开始获得这些好处。

但是,混合版本程序无法获得完全空安全应用程序具有的 运行时 健全性保证。 null 可能从非空安全库泄漏到空安全代码中,因为阻止这种情况会破坏未迁移代码的现有行为。

为了在为完全空安全的程序提供健全性的同时保持与遗留库的运行时兼容性,Dart 工具支持两种模式:

  • 混合版本程序以 不健全的空安全 运行。运行时可能发生 null 引用错误,但这仅仅是因为 null 或可空类型从某些非空安全库中转义并进入空安全代码。

  • 当程序完全迁移并且 所有 库都是空安全时,它将以 健全的空安全 运行,并具有健全性带来的所有保证和编译器优化。

如果可能,健全的空安全是您想要的。如果程序的主入口点库已选择加入空安全,则 Dart 工具会自动以健全模式运行您的程序。如果您导入非空安全库,工具会打印警告以告知您它们只能以不健全的空安全运行。

增量迁移

#

因为 Dart 支持混合版本程序,所以您可以一次迁移一个库(通常是一个 Dart 文件),同时仍然能够运行您的程序及其测试。

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

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

使用迁移工具

#

您可以使用 迁移工具 进行增量迁移。要选择退出文件或目录,请单击绿色的复选框。在下图中, bin 目录中的所有文件都被选择退出。

迁移工具中文件查看器的屏幕截图

每个选择退出的文件都将保持不变,除了 2.9 语言版本注释 。您可以稍后再次运行 dart migrate 以继续迁移。任何已迁移的文件都具有一个禁用的复选框:一旦文件已迁移,您就不能取消迁移它。

手动迁移

#

如果您想手动增量迁移一个包,请按照以下步骤操作:

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

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

    $ dart pub get

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

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

  4. 在您当前迁移期间不想考虑的任何 Dart 文件的顶部添加 语言版本注释

    dart
    // @dart=2.9

    对于位于 2.12 包中的库使用语言版本 2.9 可以减少来自未迁移代码的分析错误(红色波浪线)。但是, 不健全的空安全会减少分析器可以使用的信息。 例如,分析器可能假设参数类型不可为空,即使 2.9 文件可能传入 null 值。

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

测试或运行混合版本程序

#

要测试或运行混合版本代码,您需要禁用健全的空安全。您可以通过两种方式执行此操作:

  • 使用 --no-sound-null-safety 标志禁用 dartflutter 命令中的健全空安全:

    $ dart --no-sound-null-safety run
    $ flutter run --no-sound-null-safety
  • 或者,将入口点(包含 main() 函数的文件)中的语言版本设置为 2.9。在 Flutter 应用程序中,此文件通常名为 lib/main.dart 。在命令行应用程序中,此文件通常名为 bin/<packageName>.dart 。您还可以选择退出 test 下的文件,因为它们也是入口点。示例:

    dart
    // @dart=2.9
    import 'src/my_app.dart';
    
    void main() {
      //...
    }

使用这两种机制中的任何一种选择退出测试对于在增量迁移过程中进行测试非常有用,但是这样做意味着您没有在启用完全空安全的情况下测试代码。当您完成库的增量迁移后,务必将测试选择 加入 空安全。