目录

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<_>
  • 当整个空合并表达式 (e1 ?? e2) 的上下文为 dynamic 时,e2 的上下文现在为 e1 的静态类型。

Dart 3.4

#

发布于 2024 年 5 月 14 日 | Dart 3.4 公告

Dart 3.4 对类型分析进行了多项改进。这些包括

  • 改进了条件表达式、空合并表达式和赋值以及 switch 表达式的类型分析。
  • 使 cast 模式的模式上下文类型模式与规范对齐。
  • 使 map 和 set 字面量的可空传播运算符 (...?) 的类型模式可为空,以匹配 list 字面量的行为。

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.
    }
  • 如果不存在冲突的声明,则现在可以根据私有最终字段提升的规则提升抽象 getter。

Dart 3.2

#

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

Dart 3.2 对流程分析进行了增强,包括

  • 扩展了类型提升,使其适用于私有最终字段。以前仅适用于局部变量和参数,现在私有最终字段可以通过空检查和 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
      }
    }

    有关私有最终字段何时可以提升以及何时不能提升的更多信息,请查看修复类型提升失败

  • 更正了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 的 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', () {
    // 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 从测试版升级到稳定版通道。

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 添加了对 set 字面量的支持:

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(包括 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 团队如何以及为何开发此版本控制方法,请查看语言版本控制规范