Dart 语言演进
此页面列出了 Dart 编程语言的显著变更和新增内容。
- 要了解有关最新支持的语言版本的具体详情,请查看语言文档或语言规范。
- 有关 Dart SDK 变更的完整历史记录,请参阅 SDK 变更日志。
- 有关破坏性变更(包括语言版本化的变更)的完整历史记录,请查看破坏性变更页面。
要使用 2.0 后引入的语言特性,请设置不低于 Dart 首次支持该特性版本号的 SDK 约束。
例如:要使用 2.12 中引入的空安全,请在 pubspec.yaml
文件中将 2.12.0
设置为最低约束。
environment:
sdk: '>=2.12.0 <3.0.0'
每个版本的变化
#Dart 3.8
#发布于 2025 年 5 月 20 日 | Dart 3.8 公告
以下语言特性已添加到 Dart 3.8 中
- 空感知元素:空感知元素会在集合字面量中评估一个表达式,如果结果不是
null
,则将该值插入到周围的集合中。
以下支持特性已更新
- Dart format:Dart 3.8 的格式化程序基于先前版本的重写,整合了反馈、bug 修复和进一步增强。它现在智能地自动化尾部逗号的放置,决定是否拆分结构而不是强制拆分。更新还包括样式更改,以收紧和改进代码输出。
有关这些以及其他变更的更多信息,请参阅Dart 3.8 变更日志。
Dart 3.7
#发布于 2025 年 2 月 12 日 | Dart 3.7 公告
Dart 3.7 为语言添加了对通配符变量的支持。通配符变量是命名为 _
的局部变量或参数。通配符变量是非绑定的,因此可以多次声明而不会发生冲突。例如
Foo(_, this._, super._, void _()) {}
从 3.7 开始,dart format
命令也与语言版本关联。如果输入文件的语言版本是 3.7 或更高版本,则代码将以新的紧凑风格格式化。
新风格类似于向参数列表添加尾部逗号时获得的风格,不同之处在于现在格式化程序将为您添加和删除这些逗号。当参数或参数列表拆分时,格式化如下
longFunction(
longArgument,
anotherLongArgument,
);
您可以在变更日志中找到更多详情。
Dart 3.6
#发布于 2024 年 12 月 11 日 | Dart 3.6 公告
Dart 3.6 为语言添加了对数字分隔符下划线 (_
) 的支持。数字分隔符提高了长数字字面量的可读性。
var m = 1__000_000__000_000__000_000;
Dart 3.5
#发布于 2024 年 8 月 6 日 | Dart 3.5 公告
Dart 3.5 没有添加新的语言特性,但对类型推断期间考虑的上下文做了一些小改动。其中包括以下非语言版本化的变更
- 当
await
表达式的上下文是dynamic
时,表达式操作数的上下文现在是FutureOr<_>
。 - 当整个 if-null 表达式 (
e1 ?? e2
) 的上下文是dynamic
时,e2
的上下文现在是e1
的静态类型。
Dart 3.4
#发布于 2024 年 5 月 14 日 | Dart 3.4 公告
Dart 3.4 对类型分析进行了一些改进。其中包括
- 条件表达式、if-null 表达式和赋值以及 switch 表达式的类型分析改进。
- 将 cast 模式的模式上下文类型模式与规范对齐。
- 使 null-aware spread 运算符 (
...?
) 的类型模式对于 map 和 set 字面量可空,以匹配 list 字面量的行为。
Dart 3.3
#发布于 2024 年 2 月 15 日 | Dart 3.3 公告
Dart 3.3 为语言添加了一些增强功能
扩展类型是 Dart 中的一项新特性,允许对现有类型进行零成本包装。它们类似于包装类和扩展方法,但在实现和权衡方面有所不同。
dartextension type Meters(int value) { String get label => '${value}m'; Meters operator +(Meters other) => Meters(value + other.value); } void main() { var m = Meters(42); // Has type `Meters`. var m2 = m + m; // OK, type `Meters`. // int i = m; // Compile-time error, wrong type. // m.isEven; // Compile-time error, no such member. assert(identical(m, m.value)); // Succeeds. }
在没有冲突声明的情况下,抽象 getter 现在可以在私有 final 字段提升的规则下提升。
Dart 3.2
#发布于 2023 年 11 月 15 日 | Dart 3.2 公告
Dart 3.2 添加了对流分析的增强,其中包括
扩展了类型提升以应用于私有 final 字段。以前仅适用于局部变量和参数,现在私有 final 字段可以通过 null 检查和
is
测试提升为非空类型。例如,以下代码现在是健全的dartclass Example { final int? _privateField; Example(this._privateField); void f() { if (_privateField != null) { // _privateField has now been promoted; you can use it without // null checking it. int i = _privateField; // OK } } } // Private field promotions also work from outside of the class: void f(Example x) { if (x._privateField != null) { int i = x._privateField; // OK } }
有关私有 final 字段何时可以和何时不能提升的更多信息,请查看修复类型提升失败。
修正了 if-case 语句在匹配值抛出异常时类型提升行为中的不一致问题。
Dart 3.1
#发布于 2023 年 8 月 16 日 | Dart 3.1 公告
Dart 3.1 没有添加任何新特性,也没有对语言进行任何更改。
Dart 3.0
#发布于 2023 年 5 月 10 日 | Dart 3.0 公告
Dart 3.0 引入了几项新的主要语言特性
- 模式,一种新的语法类别,允许您匹配和解构值。
- 记录,一种新类型,允许您将不同类型的多个值聚合到单个函数返回值中。
- 类修饰符,一组新的关键字,允许您控制类或 mixin 的使用方式。
- Switch 表达式,一种新的多路分支形式,允许在预期表达式的地方使用。
- If-case 子句,一种新的条件构造,将值与模式匹配,并根据模式是否匹配执行 then 分支或 else 分支。
Dart 3.0 还引入了一些破坏性语言变更
- 不带
mixin
类修饰符的类声明不能再作为 mixins 应用。 - 如果在可选命名参数的默认值前使用冒号 (
:
) 作为分隔符,现在会产生编译时错误。请改用等号 (=
)。 - 如果
continue
语句的目标标签未附在循环语句 (for
,do
, andwhile
) 或switch
成员上,现在会产生编译时错误。
Dart 2.19
#发布于 2023 年 1 月 25 日
Dart 2.19 引入了围绕类型推断的一些注意事项。其中包括
- 更多针对不可达代码情况的流分析标志。
- 不再将不可访问的私有名称委托给
noSuchMethod
。 - 顶层类型推断在循环依赖时抛出异常。
Dart 2.19 还引入了对未命名库的支持。用于附加库级文档注释和注解的库指令,现在可以并且应该在没有名称的情况下编写
/// A really great test library.
@TestOn('browser')
library;
Dart 2.18
#发布于 2022 年 8 月 30 日 | Dart 2.18 公告
Dart 2.18 增强了类型推断。此更改允许泛型函数调用中的参数之间进行信息流。在 2.18 之前,如果在某些方法中没有指定参数的类型,Dart 会报告错误。这些类型错误会指出潜在的 null 出现。有了 2.18,编译器会根据调用中的其他值推断参数类型。您无需在代码中内联指定参数类型。
Dart 2.18 还停止支持不扩展 Object
的 mixin 类。
要了解有关这些特性的更多信息,请查看
Dart 2.17
#发布于 2022 年 5 月 11 日 | Dart 2.17 公告
Dart 2.17 通过增强枚举扩展了枚举功能。增强枚举允许枚举声明定义成员,包括字段、构造函数、方法、getter 等。
Dart 2.17 为构造函数添加了对超初始化参数的支持。超参数允许您避免手动将每个参数传递到非重定向构造函数的 super 调用中。您可以转而使用超参数将参数转发给超类构造函数。
Dart 2.17 取消了对命名参数的一些限制。命名参数现在可以自由地与位置参数交错。从 Dart 2.17 开始,您可以编写以下代码
void main() {
test(skip: true, 'A test description', () {
// Very long function body here...
});
}
要了解有关这些特性的更多信息,请查看
Dart 2.16
#发布于 2022 年 2 月 3 日 | Dart 2.16 公告
Dart 2.16 没有为 Dart 语言添加新特性。它确实扩展了 Dart 工具。
Dart 2.15
#发布于 2021 年 12 月 8 日 | Dart 2.15 公告
Dart 2.15 改进了对函数指针(称为 tear-offs)的支持。特别是,现在支持构造函数 tear-offs。
Dart 2.14
#发布于 2021 年 9 月 8 日 | Dart 2.14 公告
Dart 2.14 添加了无符号右移(或称为三位右移)运算符 (>>>
)。这个新运算符的功能与 >>
类似,不同之处在于它始终用零填充最高有效位。
要了解有关这些运算符的更多信息,请查看位运算符和移位运算符。
Dart 2.14 取消了对类型参数的一些限制。您可以将类型参数传递给注解,并使用泛型函数类型作为类型参数。从 Dart 2.14 开始,您可以编写以下代码
@TypeHelper<int>(42, "The meaning")
late List<T Function<T>(T)> idFunctions;
var callback = [<T>(T value) => value];
late S Function<S extends T Function<T>(T)>(S) f;
Dart 2.13
#发布于 2021 年 5 月 19 日 | Dart 2.13 公告
Dart 2.13 扩展了对 类型别名 (typedef
) 的支持。类型别名以前只适用于函数类型,但现在适用于任何类型。您可以在任何可以使用原始类型的地方使用通过类型别名创建的新名称。
Dart 2.13 改进了 Dart FFI 中的结构体支持,添加了对内联数组和紧凑结构体的支持。
Dart 2.12
#发布于 2021 年 3 月 3 日 | Dart 2.12 公告
Dart 2.12 添加了对 健全空安全 的支持。当您选择加入空安全时,代码中的类型默认是非空的,这意味着变量不能包含 null,除非您明确指定可以。有了空安全,您的运行时 null 解引用错误将转变为编辑时分析错误。
在 Dart 2.12 中,Dart FFI 从 Beta 版本升级到稳定通道。
Dart 2.10
#发布于 2020 年 10 月 1 日 | Dart 2.10 公告
Dart 2.10 没有为 Dart 语言添加新特性。
Dart 2.9
#发布于 2020 年 8 月 5 日
Dart 2.9 没有为 Dart 语言添加新特性。
Dart 2.8
#发布于 2020 年 5 月 6 日 | Dart 2.8 公告
Dart 2.8 没有为 Dart 语言添加任何特性。它确实包含了一些准备性的破坏性变更,以提高空安全相关的可用性和性能。
Dart 2.7
#发布于 2019 年 12 月 11 日 | Dart 2.7 公告
Dart 2.7 添加了对 扩展方法 的支持,使您能够以常规方法调用的简洁性和自动完成体验为任何类型(即使是您无法控制的类型)添加功能。
以下示例将 dart:core
中的 String
类扩展了一个新的 parseInt()
方法
extension ParseNumbers on String {
int parseInt() {
return int.parse(this);
}
}
void main() {
int i = '42'.parseInt();
print(i);
}
Dart 2.6
#发布于 2019 年 11 月 5 日 | Dart 2.6 公告
Dart 2.6 引入了一项破坏性变更 (dart-lang/sdk#37985)。其中 Null
作为 FutureOr<T>
子类型的约束,现在将 Null
作为 T
的解。
例如:以下代码现在打印 Null
。在 Dart 2.6 之前,它打印 dynamic
。匿名闭包 () {}
返回 Null
类型。
import 'dart:async';
void foo<T>(FutureOr<T> Function() f) { print(T); }
main() { foo(() {}); }
Dart 2.5
#发布于 2019 年 9 月 10 日 | Dart 2.5 公告
Dart 2.5 没有为 Dart 语言添加任何特性,但它添加了使用新的核心库 dart:ffi
从 Dart 代码调用原生 C 代码的支持。
Dart 2.4
#发布于 2019 年 6 月 27 日
Dart 2.4 引入了一项破坏性变更 dart-lang/sdk#35097。
Dart 现在强制超接口中使用的类型变量协变。例如:在此版本之前,Dart 接受以下代码,但现在拒绝它
class A<X> {};
class B<X> extends A<void Function(X)> {};
您现在可以在异步函数和生成器函数中使用 async
作为标识符。
Dart 2.3
#发布于 2019 年 5 月 8 日 | Dart 2.3 公告
Dart 2.3 添加了三个运算符,旨在改进执行列表操作的代码,例如声明式 UI 代码。
展开运算符 能够将一个列表中的元素解包到另一个列表中。在以下示例中,buildMainElements()
返回的列表被解包到传递给 children
参数的列表中
Widget build(BuildContext context) {
return Column(children: [
Header(),
...buildMainElements(),
Footer(),
]);
}
集合 if 运算符支持有条件地添加元素。以下示例添加了一个 FlatButton
元素,除非应用程序显示最后一页
Widget build(BuildContext context) {
return Column(children: [
Text(mainText),
if (page != pages.last)
FlatButton(child: Text('Next')),
]);
}
集合 for 运算符支持构建重复元素。以下示例为 sections
中的每个部分添加一个 HeadingAction
元素
Widget build(BuildContext context) {
return Column(children: [
Text(mainText),
for (var section in sections)
HeadingAction(section.heading),
]);
}
Dart 2.2
#发布于 2019 年 2 月 26 日 | Dart 2.2 公告
Dart 2.2 添加了对 集合字面量 的支持
const Set<String> currencies = {'EUR', 'USD', 'JPY'};
Dart 2.1
#发布于 2018 年 11 月 15 日 | Dart 2.1 公告
Dart 2.1 添加了对 int 到 double 转换 的支持,允许开发人员使用整数字面量设置 double
值。此特性消除了在概念上值为整数时被迫使用 double
字面量(例如,4.0
)的麻烦。
在以下 Flutter 代码中,horizontal
和 vertical
的类型是 double
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 8,
)
Dart 2.0
#发布于 2018 年 2 月 22 日 | Dart 2.0 公告
Dart 2.0 实现了一个新的健全类型系统。在 Dart 2.0 之前,类型不是完全健全的,Dart 严重依赖运行时类型检查。Dart 1.x 代码必须迁移到 Dart 2。
语言版本控制
#单个 Dart SDK 可以同时支持多个版本的 Dart 语言。编译器会确定代码的目标版本,并根据该版本解释代码。
在 Dart 引入不兼容特性(如空安全)的罕见情况下,语言版本控制变得很重要。当 Dart 引入破坏性变更时,原本可以编译的代码可能无法再编译。语言版本控制允许您设置每个库的语言版本以保持兼容性。
在空安全的情况下,Dart SDK 2.12 到 2.19 允许您选择将代码更新为使用空安全。Dart 使用语言版本控制允许非空安全代码与空安全代码一起运行。这一决定使得从非空安全代码迁移到空安全代码成为可能。要查看应用或包如何迁移到具有不兼容特性的新语言版本的示例,请查看迁移到空安全。
每个包的默认语言版本等于 pubspec.yaml
文件中 SDK 约束的下限。
例如: pubspec.yaml
文件中的以下条目表示此包默认使用 Dart 2.18 语言版本。
environment:
sdk: '>=2.18.0 <3.0.0'
语言版本号
#Dart 将其语言版本格式化为用点分隔的两个数字。它读作主要版本号和次要版本号。次要版本号可能会引入破坏性变更。
Dart 版本可能会在语言版本后附加一个补丁号。补丁除了错误修复外,不应更改语言。例如:Dart 2.18.3 是 Dart 2.18 SDK 语言版本的最新版本。
每个 Dart SDK 支持其主要版本号内的所有语言版本。这意味着 Dart SDK 2.18.3 支持 2.0 到 2.18(含)的语言版本,但不包括 Dart 1.x。
从 SDK 版本推导语言版本意味着以下几点
每当发布 SDK 的次要版本时,就会出现新的语言版本。实际上,许多这些语言版本与以前的版本工作方式非常相似,并且它们之间完全兼容。例如:Dart 2.9 语言的工作方式非常类似于 Dart 2.8 语言。
发布 SDK 的补丁版本时,它不能引入新的语言特性。例如:2.18.3 版本仍然是语言版本 2.18。它必须与 2.18.2、2.18.1 和 2.18.0 保持兼容。
按库选择语言版本
#默认情况下,包中的每个 Dart 文件都使用相同的语言版本。Dart 将默认语言版本识别为 pubspec.yaml
文件中指定的 SDK 约束的下限。有时,Dart 文件可能需要使用较旧的语言版本。例如,您可能无法同时将包中的所有文件迁移到空安全。
Dart 支持按库选择语言版本。要选择使用与包中其余部分不同的语言版本,Dart 库必须包含以下格式的注释
// @dart = <major>.<minor>
例如
// Description of what's in this file.
// @dart = 2.17
import 'dart:math';
...
@dart
字符串必须位于 //
注释中(不能是 ///
或 /*
),并且必须出现在文件中的任何 Dart 代码之前。除了 @dart
和版本字符串内部,空白字符(制表符和空格)无关紧要。如上一个示例所示,其他注释可以出现在 @dart
注释之前。
要了解 Dart 团队如何以及为何开发此版本控制方法,请查看语言版本控制规范。