Dart 3 迁移指南
Dart 3 是一个主要版本,为 Dart 引入了新的核心功能:records、patterns 和 class modifiers。
除了这些新功能之外,Dart 3 还包含一些可能会破坏现有代码的变更。
本指南将帮助您解决升级到 Dart 3 后可能遇到的任何迁移问题。
介绍
#无版本控制变更与有版本控制变更
#下面列出的潜在破坏性变更分为两类
无版本控制变更:这些变更在升级到 Dart 3.0 SDK 或更高版本后会影响所有 Dart 代码。无法“关闭”这些变更。
有版本控制变更:这些变更仅在包或应用的语言版本设置为 >= Dart 3.0 时适用。语言版本源自
pubspec.yaml
文件中sdk
的下限约束。像这样的 SDK 约束 不 会应用 Dart 3 有版本控制的变更yamlenvironment: sdk: '>=2.14.0 <3.0.0'
但像这样的 SDK 约束会应用
yamlenvironment: 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
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.
迁移
#将冒号用法改为
int someInt({int x: 0}) => x;
使用等号
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
,否则不能用作 mixins。此限制适用于任何尝试将该类用作 mixin 的库中的代码,而不管后者的语言版本如何。
范围
#这是有版本控制变更,仅适用于语言版本 3.0 或更高版本。
症状
#类似如下的分析错误
Mixin can only be applied to class.
当一个既不是 mixin class
也不是 mixin
的类用于 with
子句时,分析器会生成此诊断信息。
迁移
#确定该类是否打算用作 mixin。
如果该类定义了一个接口,请考虑使用 implements
。
switch
#Dart 3.0 将 switch case 解释为 模式 而不是常量表达式。
范围
#这是有版本控制变更,仅适用于语言版本 3.0 或更高版本。
症状
#switch case 中找到的大多数常量表达式都是具有相同含义的有效模式(命名常量、字面量等)。这些将行为相同,不会出现任何症状。
少数不是有效模式的常量表达式将触发 invalid_case_patterns
lint。
迁移
#您可以通过在 case 模式前加上 const
来恢复到原始行为,这样它就不再被解释为模式
case const [1, 2]:
case const {'k': 'v'}:
case const {1, 2}:
case const Point(1, 2):
您可以使用 dart fix
或在您的 IDE 中运行快速修复此破坏性变更。
continue
#如果 continue 语句指向的标签不是循环(for
、do
和 while
语句)或 switch 成员,Dart 3 将报告编译时错误。
范围
#这是有版本控制变更,仅适用于语言版本 3.0 或更高版本。
症状
#您将看到类似如下的错误
The label used in a 'continue' statement must be defined on either a loop or a switch member.
迁移
#如果改变行为是可接受的,将 continue
更改为指向有效的带标签语句,该语句必须附加到 for
、do
或 while
语句。
如果您想保留行为,将 continue
语句更改为 break
语句。在 Dart 的早期版本中,未指向循环或 switch 成员的 continue
语句行为类似于 break
。
Dart 3 核心库变更
#删除的 API
#破坏性变更 #49529:核心库已清理,移除了已弃用多年的 API。以下 API 不再存在于 Dart 核心库中。
范围
#这是无版本控制变更,适用于所有 Dart 3 代码。
dart:core
#- 移除了已弃用的
List
构造函数,因为它不是空安全的。使用列表字面量(例如空列表的[]
或空类型化列表的<int>[]
)或List.filled
。这仅影响非空安全代码,因为空安全代码已无法使用此构造函数。 - 移除了
int.parse
、double.parse
和num.parse
上已弃用的onError
参数。改用tryParse
方法。 - 移除了已弃用的
proxy
和Provisional
注解。原始的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
#- 移除了已弃用的
DeferredLibrary
类。改用deferred as
导入语法。
dart:developer
#- 移除了已弃用的
MAX_USER_TAGS
常量。改用maxUserTags
。 - 移除了已弃用的
Metrics
、Metric
、Counter
和Gauge
类,因为它们自 Dart 2.0 起已损坏。
dart:html
#- 如先前宣布,
Document
和HtmlDocument
中已弃用的registerElement
和registerElement2
方法已被移除。详见 #49536。
dart:math
#Random
接口只能实现,不能扩展。
dart:io
#- 更新
NetworkProfiling
以适应 vm_service:11.0.0 中引入的新的String
ids
症状
#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
,表示它们仅 intended 作为接口。
dart:core
#Function
类型不能再被实现、扩展或混入。自 Dart 2.0 起,出于向后兼容性,允许编写implements Function
,但它没有产生任何效果。在 Dart 3.0 中,Function
类型是 final 的,不能被子类型化,防止代码错误地认为它有效。以下声明只能实现,不能扩展
Comparable
Exception
Iterator
Pattern
Match
RegExp
RegExpMatch
StackTrace
StringSink
这些声明都不包含任何可继承的实现。它们被标记为
interface
,表示它们仅 intended 作为接口。以下声明不能再被实现或扩展
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 替代项 | 弃用 | 停用 |
---|---|---|---|
stagehand | dart create | 2.14 | 2.14* |
dartfmt | dart format | 2.14 | 2.15 |
dart2native | dart compile exe | 2.14 | 2.15 |
dart2js | dart compile js | 2.17 | 2.18 |
dartdevc | webdev | 2.17 | 2.18 |
dartanalyzer | dart analyze | 2.16 | 2.18 |
dartdoc | dart doc | 2.16 | 2.17 |
pub | dart pub | 2.15 | 2.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.
迁移
#替换分析器配置的这一部分
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
为
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 代码。