目录

Dart 3 迁移指南

Dart 3 是一个主要版本,为 Dart 引入了新的核心功能:记录模式类修饰符

除了这些新功能外,Dart 3 还包含许多可能破坏现有代码的更改。

本指南将帮助您解决升级到 Dart 3后可能遇到的任何迁移问题。

简介

#

未版本化与版本化更改

#

下面列出的潜在破坏性更改分为两类

  • 未版本化更改:这些更改在升级到 Dart 3.0 SDK 或更高版本后会影响任何 Dart 代码。没有办法“关闭”这些更改。

  • 版本化更改:这些更改仅在包或应用程序的语言版本设置为 >= Dart 3.0 时适用。语言版本pubspec.yaml 文件中的 sdk 下限约束派生。像这样的 SDK 约束应用 Dart 3 版本化更改

    yaml
    environment:
      sdk: '>=2.14.0 <3.0.0'

    但是像这样的 SDK 约束会应用

    yaml
    environment:
      sdk: '>=3.0.0 <4.0.0'

要使用新的 Dart 3 功能,您必须将语言版本更新到 3.0。这会同时获得 Dart 3 版本化更改。

Dart 3 向后兼容性

#

许多使用 Dart 2.12 或更高版本的空安全的包和应用程序可能与 Dart 3 向后兼容。对于 SDK 约束下限为 2.12.0 或更高的任何包来说,这是可能的。

Dart 的 pub 工具允许解析,即使上限限制为 3.0.0 以下的版本也是如此。例如,具有以下约束的包将被允许使用 Dart 3.x SDK 进行解析,因为当较低约束为 2.12 或更高时,pub 会将上限约束 <3.0.0 重新解释为 <4.0.0

yaml
environment:
  sdk: '>=2.14.0 <3.0.0'           # This is interpreted as '>=2.14.0 <4.0.0'

这允许开发人员将 Dart 3 健全的空安全与已经支持 2.12 空安全的包一起使用,而无需进行第二次迁移,除非代码受到任何其他 Dart 3 更改的影响。

测试影响

#

要了解您的源代码是否受到任何 Dart 3 更改的影响,请使用以下步骤

$ dart --version    # Make sure this reports 3.0.0 or higher.
$ dart pub get      # This should resolve without issues.
$ dart analyze      # This should pass without errors.

如果 pub get 步骤失败,请尝试升级您的依赖项,看看是否有更新的版本可能支持 Dart 3

$ dart pub upgrade
$ dart analyze      # This should pass without errors.

或者,如果需要,还包括主要版本升级

$ dart pub upgrade --major-versions
$ dart analyze      # This should pass without errors.

Dart 3 语言更改

#

100% 健全的空安全

#

Dart 2.12 在两年多前引入了空安全。在 Dart 2.12 中,用户需要使用 pubspec 设置启用空安全。在 Dart 3 中,空安全是内置的;您无法将其关闭。

范围

#

这是一个未版本化的更改,适用于所有 Dart 3 代码。

症状

#

在没有空安全支持的情况下开发的包会在使用 pub get 解析依赖项时导致问题

$ dart pub get

Because pkg1 doesn't support null safety, version solving failed.
The lower bound of "sdk: '>=2.9.0 <3.0.0'" must be 2.12.0 or higher to enable null safety.

使用语言版本注释选择 2.12 以下的任何语言版本来选择退出空安全的库将导致分析或编译错误

$ dart analyze .
Analyzing ....                         0.6s

  error • lib/pkg1.dart:1:1 • The language version must be >=2.12.0. 
  Try removing the language version override and migrating the code.
  • illegal_language_version_override
$ dart run bin/my_app.dart
../pkg1/lib/pkg1.dart:1:1: Error: Library doesn't support null safety.
// @dart=2.9
^^^^^^^^^^^^

迁移

#

在开始任何迁移到 Dart 3 之前,请确保您的应用程序或包已 100% 迁移以启用空安全。这需要 Dart 2.19 SDK,而不是 Dart 3 SDK。要了解如何首先迁移您的应用程序或包以支持空安全,请查看空安全迁移指南

用于默认值的冒号语法

#

由于历史原因,命名的可选参数可以使用 := 指定其默认值。在 Dart 3 中,只允许使用 = 语法。

范围

#

这是一个版本化的更改,仅适用于语言版本 3.0 或更高版本。

症状

#

Dart 分析会产生如下错误

line 2 • Using a colon as a separator before a default value is no longer supported.

迁移

#

从使用冒号更改

dart
int someInt({int x: 0}) => x;

到使用等号

dart
int someInt({int x = 0}) => x;

此迁移可以手动完成,也可以使用 dart fix 自动化完成

$ dart fix --apply --code=obsolete_colon_for_default_value

mixin

#

在 Dart 3 之前,任何 class 都可以用作 mixin,只要它没有声明的构造函数,也没有 Object 之外的超类。

在 Dart 3 中,在语言版本 3.0 或更高版本的库中声明的类不能用作混入,除非标记为 mixin。此限制适用于尝试将该类用作混入的任何库中的代码,无论后一个库的语言版本如何。

范围

#

这是一个版本化的更改,仅适用于语言版本 3.0 或更高版本。

症状

#

一个分析错误,例如

Mixin can only be applied to class.

当在 with 子句中使用既不是 mixin class 也不是 mixin 的类时,分析器会生成此诊断。

迁移

#

确定该类是否旨在用作混入。

如果该类定义了一个接口,请考虑使用 implements

switch

#

Dart 3.0 将switch case 解释为模式,而不是常量表达式。

范围

#

这是一个版本化的更改,仅适用于语言版本 3.0 或更高版本。

症状

#

switch case 中发现的大多数常量表达式都是具有相同含义的有效模式(命名常量、字面量等)。它们的行为将相同,不会出现任何症状。

少数不是有效模式的常量表达式将触发invalid_case_patterns lint

迁移

#

您可以通过在 case 模式前加上 const 来恢复到原始行为,这样它就不再被解释为模式

dart
case const [1, 2]:
case const {'k': 'v'}:
case const {1, 2}:
case const Point(1, 2):

您可以通过使用 dart fix 或从您的 IDE 中运行此重大更改的快速修复。

continue

#

如果 continue 语句的目标不是循环(fordowhile 语句)或 switch 成员,Dart 3 会报告编译时错误。

范围

#

这是一个版本化的更改,仅适用于语言版本 3.0 或更高版本。

症状

#

您将看到如下错误

The label used in a 'continue' statement must be defined on either a loop or a switch member.

迁移

#

如果更改行为是可以接受的,请将 continue 更改为指向有效的带标签的语句,该语句必须附加到 fordowhile 语句。

如果要保留行为,请将 continue 语句更改为 break 语句。在之前的 Dart 版本中,未指向循环或 switch 成员的 continue 语句的行为类似于 break

Dart 3 核心库更改

#

已删除的 API

#

重大更改 #49529:核心库已清理,移除了已弃用多年的 API。以下 API 不再存在于 Dart 核心库中。

范围

#

这是一个未版本化的更改,适用于所有 Dart 3 代码。

dart:core

#
  • 移除了已弃用的 List 构造函数,因为它不是空安全的。请使用列表字面量(例如,空列表用 [],空类型列表用 <int>[])或 List.filled。这只会影响非空安全代码,因为空安全代码已经不能使用此构造函数。
  • 移除了 int.parsedouble.parsenum.parse 中已弃用的 onError 参数。请改用 tryParse 方法。
  • 移除了已弃用的 proxyProvisional 注解。原始的 proxy 注解在 Dart 2 中没有任何效果,Provisional 类型和 provisional 常量仅在 Dart 2.0 开发过程中内部使用。
  • 移除了已弃用的 Deprecated.expires getter。请改用 Deprecated.message
  • 移除了已弃用的 CastError 错误。请改用 TypeError
  • 移除了已弃用的 FallThroughError 错误。之前抛出此错误的 fall-through 行为在 Dart 2.0 中已变为编译时错误。
  • 移除了已弃用的 NullThrownError 错误。此错误永远不会从空安全代码中抛出。
  • 移除了已弃用的 AbstractClassInstantiationError 错误。在 Dart 2.0 中,调用抽象类的构造函数已变为编译时错误。
  • 移除了已弃用的 CyclicInitializationError。在空安全代码中,不再在运行时检测循环依赖。此类代码将以其他方式失败,可能会出现 StackOverflowError。
  • 移除了已弃用的 NoSuchMethodError 默认构造函数。请改用 NoSuchMethodError.withInvocation 命名构造函数。
  • 移除了已弃用的 BidirectionalIterator 类。现有的双向迭代器仍然可以工作,只是它们没有共享的超类型将它们锁定为特定的向后移动名称。

dart:async

#

dart:developer

#

dart:html

#
  • 如先前宣布的那样,已移除 DocumentHtmlDocument 中已弃用的 registerElementregisterElement2 方法。有关详细信息,请参阅 #49536

dart:math

#
  • Random 接口只能被实现,而不能被扩展。

dart:io

#
  • 更新 NetworkProfiling 以适应 vm_service:11.0.0 中引入的新 String id。

症状

#

Dart 分析(例如,在您的 IDE 中,或在 dart analyze/flutter analyze 中)将因如下错误而失败:

error line 2 • Undefined class 'CyclicInitializationError'.

迁移

#

手动迁移,不再使用这些 API。

extends & implements

#

Dart 3 支持新的类修饰符,可以限制类的功能。它们已应用于核心库中的许多类。

范围

#

这是一个版本化的更改,仅适用于语言版本 3.0 或更高版本。

dart:async

#
  • 以下声明只能被实现,而不能被扩展

    • StreamConsumer
    • StreamIterator
    • StreamTransformer
    • MultiStreamController

    这些声明中没有包含任何可以继承的实现。它们被标记为 interface,表示它们仅用作接口。

dart:core

#
  • Function 类型不能再被实现、扩展或混入。自 Dart 2.0 以来,为了向后兼容,允许编写 implements Function,但它没有任何效果。在 Dart 3.0 中,Function 类型是 final 的,不能被子类型化,从而防止代码错误地假设它可以工作。

  • 以下声明只能被实现,而不能被扩展

    • Comparable
    • Exception
    • Iterator
    • Pattern
    • Match
    • RegExp
    • RegExpMatch
    • StackTrace
    • StringSink

    这些声明中没有包含任何可以继承的实现。它们被标记为 interface,表示它们仅用作接口。

  • 以下声明不能再被实现或扩展

    • MapEntry
    • OutOfMemoryError
    • StackOverflowError
    • Expando
    • WeakReference
    • Finalizer

    MapEntry 值类受到限制,以便稍后进行优化。其余的类与平台紧密耦合,不打算被子类化或实现。

dart:collection

#
  • 以下接口不能再被扩展,只能被实现

    • Queue
  • 以下实现类不能再被实现

    • LinkedList
    • LinkedListEntry
  • 以下实现类不能再被实现或扩展

    • HasNextIterator(也已弃用。)
    • HashMap
    • LinkedHashMap
    • HashSet
    • LinkedHashSet
    • DoubleLinkedQueue
    • ListQueue
    • SplayTreeMap
    • SplayTreeSet

Dart 3 工具更改

#

已删除的工具

#

从历史上看,Dart 团队为诸如格式化代码 (dartfmt)、分析代码 (dartanalyzer) 等提供了一些较小的开发人员工具。在 Dart 2.10(2020 年 10 月)中,我们引入了一个新的统一 Dart 开发人员工具,即 dart 工具

范围

#

这是一个未版本化的更改,适用于所有 Dart 3 代码。

症状

#

在 Dart 3 中,这些较小的工具不存在,已被新的组合 dart 工具取代。

迁移

#

使用 dart 工具中可用的新子命令

历史工具dart 替换弃用停止使用
stagehanddart create2.142.14*
dartfmtdart format2.142.15
dart2nativedart compile exe2.142.15
dart2jsdart compile js2.172.18
dartdevcwebdev2.172.18
dartanalyzerdart analyze2.162.18
dartdocdart doc2.162.17
pubdart pub2.152.17

空安全迁移工具

#

以下空安全迁移命令已被删除,因为 Dart 3 不支持没有空安全的代码

  • dart migrate
  • dart pub upgrade --null-safety
  • dart pub outdated --mode=null-safety

范围

#

这是一个未版本化的更改,适用于所有 Dart 3 代码。

症状

#

这些命令将失败。

迁移

#

使用 Dart 2.19 迁移到空安全

分析器配置

#

用于启用更严格检查的分析器配置选项已更改。

范围

#

这是一个未版本化的更改,适用于所有 Dart 3 代码。

症状

#

以前的配置选项将因如下警告而失败:

The option 'implicit-casts' is no longer supported.
Try using the new 'strict-casts' option.

迁移

#

替换分析器配置的这一部分

yaml
analyzer:
  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

使用

yaml
analyzer:
  language:
    strict-casts: true
    strict-raw-types: true

其他工具更改

#
  • 已弃用的 Observatory 默认已隐藏。我们建议使用 DevTools
  • 命令 dart format fix 已被 dart fix 替换 #1153
  • SDK 中捆绑用于 Dart Web 编译器的快照文件已清理 #50700
  • dart format 的输出对于某些代码 略有变化。
  • 结束对 Windows 上 pub-cache 旧位置的向后兼容性。在 Dart 3 之前,%APPDATA%\Pub\Cache 是 pub-cache 的备用位置。从 Dart 3 开始,默认的 pub-cache 位于 %LOCALAPPDATA%\Pub\Cache。如果您已将全局激活的软件包添加到您的 PATH,请考虑更新 PATH 以包含 %LOCALAPPDATA%\Pub\Cache\bin

范围

#

这是一个未版本化的更改,适用于所有 Dart 3 代码。