[译] Dart 3 发布了
原文 https://medium.com/dartlang/announcing-dart-3-53f065a10635
https://ducafecat.com/blog/dart-3
来自 Google I/O 2023 的问候。今天,我们在 Mountain View 现场宣布 Dart 3——迄今为止最大的 Dart 发布!Dart 3 包含三个主要进展。首先,我们完成了通往 100% 无空安全的旅程。其次,我们为记录、模式和类修饰符添加了重大的新语言特性。第三,我们预览了未来,通过 Wasm 编译,我们将扩大我们的平台支持,为 web 提供本地代码支持。现在,让我们进入细节。
100% 无空安全
在过去的四年里,我们将 Dart 发展成了一种快速、便携、现代化的语言。现在,通过 Dart 3,它是一种 100% 无空安全的语言!正如我们之前所讨论的,我们认为没有其他编程语言曾经为现有语言添加过无空安全。所以,这是一个相当漫长的旅程。
在 Dart 中实现了 100% 的 null 安全之后,我们拥有了 sound 类型系统。您可以信任,如果一个类型说一个值不是 null
,那么它永远不会是 null
。这避免了某些类别的编程错误,如空指针异常。它还允许我们的编译器和运行时以不可能没有空安全的方式优化代码。这个设计选择涉及到一个折衷。虽然迁移变得有点困难,但我们认为我们为 Dart 做出了正确的选择。
迁移到 Dart 3
实现 sound null safety 的一个关键部分是 Dart 社区的不懈支持:pub.dev 的前 1000 个包中有 99% 支持 null safety!
鉴于此,我们预计已经迁移到 null safety 的绝大多数包和应用程序将与 Dart 3 兼容。只有在少数情况下,Dart 3 中的一些相关清理可能会影响一些代码。一些旧的核心库 API 已经被删除(#34233, #49529),一些工具已经进行了调整(#50707)。如果您在使用 Dart 3 SDK 迁移时遇到任何问题,请参阅 Dart 3 迁移指南。除此之外,我们希望您会喜欢新的理性化核心库和工具。
主要语言特性——记录、模式和类修饰符
Dart 3 不仅是改变现有语言的问题。它还添加了重要的新功能和能力!这些包括记录、模式和类修饰符。
使用记录构建结构化数据
传统上,Dart 函数只能返回单个值。因此需要返回多个值的函数必须将它们打包到其他数据类型中,例如映射或列表,或定义可以保存值的新类。使用未打印的数据结构会削弱类型安全性。必须定义新类以仅仅携带数据会在编码过程中增加摩擦。您已经非常清楚地告诉了我们:多返回值的语言请求是我们的 第四高评级问题。
使用记录,您可以使用漂亮而简洁的语法构建结构化数据。考虑这个函数。它读取 JSON 块的名称和年龄,并将它们都以记录形式返回:
(String, int) userInfo(Map<String, dynamic> json) {
return (json['name'] as String, json['height'] as int);
}
这应该很熟悉所有的 Dart 开发人员。记录看起来像列表文字,例如 [‘Michael’, ‘Product Manager’]
,但使用括号而不是方括号。在 Dart 中,记录是一个通用特性。它们可以用于超过函数返回值的用途。您还可以将它们存储在变量中,将它们放入列表中,在映射中使用它们作为键,或创建包含其他记录的记录。您可以添加未命名字段,就像我们在先前的示例中所做的那样,也可以添加命名字段,如 (42, description: ‘Meaning of life’)
。
记录是值类型,没有身份。这使得编译器在某些情况下可以完全擦除记录对象。记录还带有自动定义的 ==
运算符和 hashCode
函数。记录文档中有更多细节。
使用模式和模式匹配处理结构化数据
记录简化了构建结构化数据的方式。这并不取代使用类构建更正式的类型层次结构。它只是提供了另一种选择。在任何情况下,您可能需要将该结构化数据分解为其各个元素以处理它们。这就是模式匹配发挥作用的地方。
考虑模式的基本形式。以下记录模式将记录分解为两个新变量 name
和 height
。然后,这些变量可以像任何其他变量一样使用,例如在调用 print
中:
var (String name, int height) = userInfo({'name': 'Michael', 'height': 180});
print('User $name is $height cm tall.');
类似的模式存在于列表和映射中。对于所有这些,您可以使用下划线模式跳过单个元素:
var (String name, _) = userInfo(…);
当在 switch 语句中使用时,模式会发挥作用。Dart 从一开始就具有有限的 switch 支持。在 Dart 3 中,我们扩展了 switch
语句的功能和表达力。我们现在支持在这些情况下进行模式匹配。我们已经删除了在每个 case 结尾添加 break
的需要。我们还支持逻辑运算符来组合 case。以下示例显示了一个漂亮而简洁的 switch
语句,该语句解析字符代码:
switch (charCode) {
case slash when nextCharCode == slash:
skipComment();
case slash || star || plus || minus:
operator(charCode);
case >= digit0 && <= digit9:
number();
default:
invalid();
}
当需要每个 case
中有一个或多个语句时,switch
语句提供了很好的帮助。在某些情况下,您只需要计算一个值。对于这种用例,我们提供了一个非常简洁的 switch expression。这类似于 switch statement,但使用不同的语法,这些语法被调整为表达式。以下示例函数返回 switch 表达式的值,以计算今天的工作日描述:
String describeDate(DateTime dt) =>
switch (dt.weekday) {
1 => 'Feeling the Monday blues?',
6 || 7 => 'Enjoy the weekend!',
_ => 'Hang in there.'
};
模式的一个强大功能是检查“穷尽性”,该功能确保 switch 处理所有可能的情况。在上一个示例中,我们处理了 weekday 的所有可能值,它是一个 int
。通过为特定值 1
、6
或 7
的匹配语句组合,然后使用默认情况 _
处理剩余的情况,我们穷尽了所有可能的值。为了对用户定义的数据层次结构(例如,类层次结构)启用此检查,请在类层次结构的顶部使用新的 sealed
修饰符,如以下示例:
sealed class Animal { … }
class Cow extends Animal { … }
class Sheep extends Animal { … }
class Pig extends Animal { … }
String whatDoesItSay(Animal a) =>
switch (a) { Cow c => '$c says moo', Sheep s => '$s says baa' };
这将返回以下错误,提醒我们漏掉了最后一个可能的子类型,Pig:
line 6 • The type 'Animal' is not exhaustively matched by the switch cases
since it doesn't match 'Pig()'.
最后,if
语句也可以使用模式。在下一个示例中,我们使用 if-case 匹配来匹配一个 map-pattern 来解构 JSON 映射。在其中,我们针对常量值(如 'name'
和 'Michael'
)和类型测试模式 int h
进行匹配以读取 JSON 值。如果模式匹配失败,Dart 将执行 else
语句。
final json = {'name': 'Michael', 'height': 180};
// Find Michael's height.
if (json case {'name': 'Michael', 'height': int h}) {
print('Michael is $h cm tall.');
} else {
print('Error: json contains no height info for Michael!');
}
这只涉及到您可以使用模式的所有内容。我们相信它们将在所有 Dart 代码中变得普遍。要了解更多,请查看 模式文档 和 模式 codelab。
类修饰符为类提供细粒度的访问控制
Dart 3 的第三个语言特性是类修饰符。与我们期望每个 Dart 开发人员都使用的记录和模式不同,这更像是一个高级用户功能。它解决了 Dart 开发人员构建大型 API 表面或构建企业级应用程序的需求。
类修饰符使 API 作者能够仅支持特定的功能集。默认值保持不变。我们希望 Dart 保持简单和易于接近。因此,像以前一样,常规类可以 构造、扩展 和 实现,如以下示例所示:
class Vehicle {
String make; String model;
void moveForward(int meters) { … }
}
// Construct.
var myCar = Vehicle(make: 'Ford', model: 'T',);
// Extend.
class Car extends Vehicle {
int passengers;
}
// Implement.
class MockVehicle implements Vehicle {
@override void moveForward …
}
类修饰符支持添加限制。考虑一些示例用例:
-
使用 interface class
,您可以定义其他人要实现的协议。接口类无法扩展。 -
使用 base class
,您可以确保您的所有类的子类型都从它继承,而不是实现其接口。这确保了所有实例上都可以使用私有方法。 -
使用 final class
,您可以关闭类型层次结构,防止在您自己的库之外创建任何子类。作为示例的好处是,这允许 API 拥有者添加新成员而不会冒着破坏 API 消费者的风险。
有关详细信息,请参见新的class modifiers documentation。
展望未来
Dart 3 不仅是一个新功能的重要进步,我们还为您提供了未来的预览。
Dart 语言
记录、模式和类修饰符是非常重要的新功能,因此它们的设计可能仍有改进之处。我们将继续监控您的反馈意见,如果需要,在 Dart 3 后的小版本中进行更新。
我们还在研究一些更小、更增量的功能,这些功能完全不会破坏任何代码,并且专注于提高开发者的生产力。我们正在探索的两个例子是内联类,用于使用零成本“包装器”封装现有类型,以及主构造函数; 这是一项功能,它引入了一个更简洁的语法,用于定义具有少量字段和主构造函数的类。
我们之前讨论过宏(也称为元编程)。我们特别关注此功能,以实现更好的 JSON 反序列化(及类似操作),以及实现数据类。鉴于元编程的规模和固有风险,我们采取了非常彻底的方法,因此没有具体时间表可分享,甚至无法最终确定设计决策。
原生互操作
移动设备和桌面应用程序通常依赖于由本地平台提供的许多 API,无论是通知、支付还是获取手机位置。传统上,在 Flutter 中通过构建插件来访问这些 API,这需要编写 Dart 代码和一堆特定于平台的代码来提供实现。
我们已经支持使用[dart:ffi](<https://dart.dev/guides/libraries/c-interop>)
编译为 C 库的代码进行互操作。我们目前正在扩展此功能,以支持在 Android 上的Java 和 Kotlin 互操作,以及在 iOS/macOS 上的Objective C 和 Swift 互操作。要了解 Android 互操作的介绍,请查看 Google I/O 23 的新Android 互操作视频。
编译为 WebAssembly —— 使用本机代码定向 Web
WebAssembly(缩写为 Wasm)作为跨现代浏览器的平台中立二进制指令格式而不断成熟。Flutter 框架已经使用 Wasm 一段时间了。这是我们通过一个 Wasm 编译模块将用 C++ 编写的 SKIA 图形渲染引擎传递到浏览器中的方式。我们长期以来一直有兴趣将 Wasm 用于部署 Dart 代码,但我们一直受阻。像许多其他面向对象语言一样,Dart 使用垃圾回收。在过去的一年里,我们与 Wasm 生态系统中的几个团队合作,为 WebAssembly 标准添加了一个新的 WasmGC 功能。这在 Chromium 和 Firefox 浏览器中已经接近稳定。
我们将 Dart 编译为 Wasm 模块的工作对于 Web 应用程序有两个高层次的目标:
-
加载时间:我们希望可以通过 Wasm 提供部署负载,使浏览器能够更快地加载,从而提高用户与 Web 应用程序交互所需的时间。 -
性能:由 JavaScript 驱动的 Web 应用程序需要即时编译才能实现良好的性能。Wasm 模块更接近底层和机器代码,因此我们认为它们可以提供更高的性能,减少卡顿并提供更一致的帧速率。 -
语义一致性:Dart 自豪地表示在我们支持的平台之间高度一致。然而,在 Web 上,这还存在一些例外情况。例如,Dart Web 当前在 数字的表示方式上有所不同。使用 Wasm 模块,我们将能够将 Web 视为类似其他本机目标的平台,其语义类似。
我们很高兴地宣布 Dart 到 Wasm 编译的第一个预览版!我们最初的重点是 Flutter Web 支持。现在还处于早期阶段,我们还有很多工作要完成,但我们邀请您进行实验,看看这是否和我们一样令人兴奋。
结束语
感谢您阅读到最后。我们希望这篇文章让您对 Dart 3 感到兴奋,它今天在独立的Dart SDK和Flutter 3.10 SDK中都可以使用。
我们通过声音的空值安全、核心库和工具清理完成了 Dart 语言的重大改造。有重大的新语言功能,使 Dart 更具表现力和清晰度,拥有记录和模式。对于大型 API 表面,类修饰符可以实现详细的控制。我们还包括了未来的预览,即我们即将支持 WebAssembly。
凭借所有这些功能,我们认为 Dart 3 展示了我们的长期愿景:建立最具生产力的编程语言,用于在任何平台上构建快速应用程序。我们希望您也这样认为!
© 猫哥 ducafecat.com
end
本文由 mdnice 多平台发布