内容

Dart 语言演变

此页面列出了 Dart 编程语言的重大更改和新增内容。

要使用 2.0 之后引入的语言功能,请设置一个 SDK 约束,该约束不低于 Dart 首次支持该功能的版本。

例如: 要使用在 2.12 中引入的空安全,请在 pubspec.yaml 文件中将 2.12.0 设置为较低的约束。

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

每个版本的更改

#

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 表达式的类型分析。
  • 使强制转换模式的模式上下文类型模式与规范保持一致。
  • 使空感知扩展运算符 (...?) 的类型模式对于映射和集合字面量可为空,以匹配列表字面量的行为。

Dart 3.3

#

2024 年 2 月 15 日发布 | Dart 3.3 公告

Dart 3.3 对语言添加了一些增强功能

  • 扩展类型 是 Dart 中一项新功能,允许对现有类型进行零成本包装。它们类似于包装类和扩展方法,但实现差异和权衡不同。

    dart
    extension 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.
    }
  • 如果不存在冲突的声明,现在抽象获取器可以在 私有 final 字段提升 的规则下进行提升。

Dart 3.2

#

2023 年 11 月 15 日发布 | Dart 3.2 公告

Dart 3.2 对流分析添加了增强功能,包括

  • 扩展了 类型提升 以适用于私有 final 字段。以前仅适用于局部变量和参数,现在私有 final 字段可以通过空检查和 is 测试提升为非空类型。例如,以下代码现在是健全的

    dart
    class 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 引入了几个新的主要语言功能

  • 模式 是一种新的语法类别,允许您匹配和解构值。
  • 记录 是一种新类型,允许您将不同类型的多个值聚合到单个函数返回值中。
  • 类修饰符 是一组新的关键字,允许您控制如何使用类或混合。
  • switch 表达式 是一种新的多路分支形式,允许在需要表达式的场合使用。
  • if-case 子句 是一种新的条件结构,它将一个值与一个模式匹配,并根据模式是否匹配执行 then 或 else 分支。

Dart 3.0 还引入了一些重大语言变更

  • 没有 mixin 类修饰符的类声明不再可以作为混合应用。
  • 如果使用冒号 (:) 作为可选命名参数的默认值之前的分隔符,现在将是编译时错误。请改为使用等号 (=)。
  • 如果 continue 语句的目标是未附加到循环语句 (fordowhile) 或 switch 成员的标签,现在将是编译时错误。

Dart 2.19

#

发布于 2023 年 1 月 25 日

Dart 2.19 在类型推断方面引入了一些注意事项。这些包括

  • 更多用于无法访问代码情况的流分析标志。
  • 不再将无法访问的私有名称委托给 noSuchMethod
  • 顶级类型推断在循环依赖关系中引发异常。

Dart 2.19 还引入了对无名库的支持。库指令用于追加库级别的文档注释和注解,现在可以并且应该不带名称编写

dart
/// A really great test library.
@TestOn('browser')
library;

Dart 2.18

#

发布于 2022 年 8 月 30 日 | Dart 2.18 公告

Dart 2.18 增强了类型推断。此更改允许在泛型函数调用中的参数之间进行信息流动。在 2.18 之前,如果在某些方法中没有指定参数的类型,Dart 会报告错误。这些类型错误引用了潜在的空值出现。在 2.18 中,编译器从调用中的其他值推断出参数类型。无需内联指定参数类型。

Dart 2.18 还停止支持不扩展 Object 的混合类。

要了解有关这些功能的更多信息,请查看

Dart 2.17

#

发布于 2022 年 5 月 11 日 | Dart 2.17 公告

Dart 2.17 通过增强枚举扩展了枚举功能。增强枚举允许枚举声明定义成员,包括字段、构造函数、方法、getter 等。

Dart 2.17 添加了对构造函数中超级初始化参数的支持。超级参数允许您避免必须手动将每个参数传递到非重定向构造函数的超级调用中。相反,您可以使用超级参数将参数转发到超类构造函数。

Dart 2.17 删除了对命名参数的一些限制。现在,命名参数可以自由地与位置参数交织。从 Dart 2.17 开始,您可以编写以下代码

dart
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 改进了对函数指针的支持,称为截取。特别是,现在支持构造函数截取。

Dart 2.14

#

发布于 2021 年 9 月 8 日 | Dart 2.14 公告

Dart 2.14 添加了无符号移位(或三元移位)运算符 (>>>)。此新运算符的工作方式与 >> 相同,只是它总是用零填充最高有效位。

要了解有关这些运算符的更多信息,请查看 位运算和移位运算符

Dart 2.14 删除了对类型参数的一些限制。您可以将类型参数传递给注解,并使用泛型函数类型作为类型参数。从 Dart 2.14 开始,您可以编写以下代码

dart
@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 添加了对健全的空安全的支持。当您选择加入空安全时,代码中的类型默认情况下为非空,这意味着变量不能包含空值,除非您说它们可以。使用空安全,您的运行时空指针取消引用错误将变成编辑时分析错误。

在 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 添加了对扩展方法的支持,使您能够向任何类型(甚至您无法控制的类型)添加功能,并具有常规方法调用的简洁性和自动完成功能。

以下示例使用新的 parseInt() 方法扩展了来自 dart:coreString

dart
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 类型。

dart
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 代码调用本机 C 代码的支持,使用新的核心库 dart:ffi

Dart 2.4

#

发布于 2019 年 6 月 27 日

Dart 2.4 引入了一个重大更改dart-lang/sdk#35097

Dart 现在强制执行在超接口中使用的类型变量的协变性。例如:在此版本之前,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 参数的列表中

dart
Widget build(BuildContext context) {
  return Column(children: [
    Header(),
    ...buildMainElements(),
    Footer(),
  ]);
}

集合 if 运算符使能够有条件地添加元素。以下示例在应用程序不显示最后一页时添加 FlatButton 元素

dart
Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    if (page != pages.last)
      FlatButton(child: Text('Next')),
  ]);
}

集合 for 运算符使能够构建重复元素。以下示例为 sections 中的每个部分添加一个 HeadingAction 元素

dart
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 添加了对集合文字的支持

dart
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 代码中,horizontalvertical 的类型为 double

dart
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 语言版本。

yaml
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
// @dart = <major>.<minor>

例如

dart
// Description of what's in this file.
// @dart = 2.17
import 'dart:math';
...

@dart 字符串必须在 // 注释中(而不是 ////*),并且必须出现在文件中的任何 Dart 代码之前。空格(制表符和空格)无关紧要,除非在 @dart 和版本字符串中。如前面的示例所示,其他注释可以出现在 @dart 注释之前。

要了解 Dart 团队如何以及为何开发此版本控制方法,请查看语言版本控制规范