目录

Dart 语言演进

本页面列出了 Dart 编程语言的显著更改和新增内容。

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

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

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

各个版本的更改

#

Dart 3.6

#

2024年12月11日发布 | Dart 3.6 公告

Dart 3.6 为语言添加了对 数字分隔符 下划线( _ )的支持。数字分隔符提高了长数字字面量的可读性。

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

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); // 类型为 `Meters` 。
      var m2 = m + m; // 正确,类型为 `Meters` 。
      // int i = m; // 编译时错误,类型错误。
      // m.isEven; // 编译时错误,没有此成员。
      assert(identical(m, m.value)); // 成功。
    }
  • 如果没有冲突的声明,根据 私有 final 字段提升 的规则,现在可以提升抽象 getter。

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 现在已被提升;您可以使用它而无需对其进行空检查。
          int i = _privateField; // 正确
        }
      }
    }
    
    // 私有字段提升也可以从类外部进行:
    void f(Example x) {
      if (x._privateField != null) {
        int i = x._privateField; // 正确
      }
    }

    有关私有 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 类修饰符的类声明不能再用作 mixin。
  • 如果在可选命名参数的默认值之前使用冒号( : )作为分隔符,则现在是编译时错误。请改用等号 (=)。
  • 如果 continue 语句的目标标签未附加到循环语句( fordowhile )或 switch 成员,则现在是编译时错误。

Dart 2.19

#

2023年1月25日发布

Dart 2.19 引入了一些围绕类型推断的预防措施。这些措施包括:

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

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

dart
/// 一个非常棒的测试库。
@TestOn('browser')
library;

Dart 2.18

#

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

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

Dart 2.18 还停止了对不扩展 Object 的 mixin 类的支持。

要了解有关这些特性的更多信息,请查看:

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', () {
    // 这里有很长的函数体...
  });
}

要了解有关这些特性的更多信息,请查看:

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 添加了对 健全空安全 的支持。当您选择启用空安全时,代码中的类型默认为不可为空,这意味着变量不能包含 null,除非您声明它们可以。使用空安全,您的运行时空解引用错误会变成编辑时分析错误。

在 Dart 2.12 中, Dart FFI 从测试版升级到稳定通道。

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:core 中的 String 类:

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:ffi 从 Dart 代码 调用本机 C 代码 的支持。

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
// 此文件的内容说明。
// @dart = 2.17
import 'dart:math';
...

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

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