中心原文链接: medium.com/dartlang/an…

自从 Flutter Forword 发布了 Dart 3 预览 之后,咱们对 Dart 3 的正式发布就一直翘首以待,这不仅仅是 Dart 版本号追上了 Flutter 版本号,更是 Dart 在 2.0 之后迎来的最大一次更新,首要包含了:

  • 100% 空安全
  • records
  • patterns
  • class modifiers
  • Wasm 对 Web 的添加支撑,能够预览 dart wasm native 了

100% 空安全支撑

如下图所示,Dart 的 null safety 历经三年的时刻,如今 Dart 终于有用了完善的类型体系,现在的 Dart 3 下,如果一个类型说一个值不是 null,那么它永远不或许是 null

Google I/O 2023 - Dart 3 正式版发布,快来看看有什么更新吧

说起来,还真有不少用户的项目没升级到 null safety ,这次就不能再等了。

别的,现在 pub.dev 上排名前 1000 的包中有 99% 支撑空安全,所以官方预计升级到 Dart 3 的兼容问题并不大,少数状况下,Dart 3 中的对一些前史代码的相关整理或许会影响某些代码的运转,例如

  • 一些旧的中心库 API 已被删去(#34233、#49529)
  • 一些东西已被调整(#50707)。

如果你在搬迁到到 Dart 3 时遇到问题,能够查阅 dart.dev/resources/d…

Record, patterns 和 class modifiers

关于万众等待的 record 和 patterns 其实在之前的 Dart 3 新特性 Record 和 Patterns 的提前预览解说上已经有个详细解释,这儿首要重新根据官方内容简诉一些这些变化。

运用 record 构建结构化数据

在此之前 Dart 函数只能回来一个值,如果需求回来多个值,必须将这些值打包成其他数据类型,例如 Map 或 List,或许界说能够保存这些值的新类。

运用非类型化数据结构削弱了类型安全性,而界说新类来传输数据会添加编码过程中的工作量,可是现在,经过 record 就能够简练明地构建结构化数据:

(String,int)userInfo(Map<String,dynamic>json) {
return(json['name']asString,json['height']asint);
}

在 Dart 中,record 是一个通用功用,它们不仅能够用于函数回来值,还能够将它们存储在变量中,例如将它们放入 List 中或许它们用作 Map 中的键,或创立包含其他 record 的 record。

别的还能够添加未命名字段,就像咱们在前面的示例中所做的那样,也能够添加命名字段,例如 (42, description: ‘Meaning of life’)

record 是值类型,没有标识,这让编译器能够在某些状况下彻底擦除记载方针,记载还带有自动界说的 == 运算符和 hashCode 函数。

详细能够参阅官方文档:dart.dev/language/re… 或许之前相关的中文材料: /post/719474…

运用具有 pattern 和 pattern 匹配的结构化数据

record 简化了构建结构化数据的方法,这不会替代运用类来构建正式的类型层次结构的方法,它仅仅供给了另一种挑选。

在任何一种状况下,你或许期望将结构化数据分解为单独的元素,这便是 pattern 匹配发挥作用的地方。

考虑 pattern 的基本形式,以下记载 pattern 将 record 解构为两个新变量 nameheight ,然后能够像任何其他变量一样运用这些变量:

var(Stringname,intheight)=userInfo({'name':'Michael','height':180});
print('User$nameis$heightcm tall.');

List 和 Map 存在相似的 pattern ,都能够运用下划线形式越过单个元素:

var(Stringname,_)=userInfo(…);

在 switch 语法中, Dart 3 扩展了句子 switch 的支撑,现在支撑在这些状况下进行 pattern 匹配:

switch(charCode) {
caseslashwhennextCharCode==slash:
 skipComment();
​
caseslash||star||plus||minus:
 operator(charCode);
​
case>=digit0&&<=digit9:
 number();
​
default:
 invalid();
}

还能够经过新的表达式进行微调,以下示例函数回来 switch 表达式的值以计算今天工作日的描绘:

StringdescribeDate(DateTimedt)=>
switch(dt.weekday) {
  1=>'Feeling the Monday blues?',
  6||7=>'Enjoy the weekend!',
  _=>'Hang in there.'
};

形式的一个强大功用是检查 “exhaustiveness” 的才干,此功用可保证 switch 处理一切或许的状况

在前面的示例中,咱们正在处理工作日的一切或许值,这是一个int ,所以咱们经过针对特定值 16/7 的匹配句子的组合来尽头一切或许的值,然后经过 _ 对其余状况运用默许状况。

要对用户界说的数据层次结构(例如类层次结构)启用该才干,请在类层次结构的顶部运用 sealed 修饰符,如下例所示:

sealedclassAnimal{…}
classCowextendsAnimal{…}
classSheepextendsAnimal{…}
classPigextendsAnimal{…}
​
StringwhatDoesItSay(Animala)=>
 switch(a) {Cowc=>'$csays moo',Sheeps=>'$ssays baa'};

这将回来以下错误,提醒咱们错过了最终一个或许的子类型 Pig 的处理:

line 6 • The type 'Animal' is not exhaustively matched by the switch cases
since it doesn't match 'Pig()'.

最终,if 句子也能够运用 pattern ,在下面的例子里,咱们运用 if-case 匹配映射形式来解构 JSON 映射,这儿匹配常量值(字符串如 'name' and 'Michael')和类型测验形式 int h 以读出 JSON 值,如果形式匹配失败,Dart 将执行该 else 句子。

finaljson={'name':'Michael','height':180};
​
// Find Michael's height.
if(jsoncase{'name':'Michael','height':inth}) {
print('Michael is$hcm tall.');
}else{
print('Error: json contains no height info for Michael!');
}

详细能够参阅官方文档:dart.dev/language/pa… 或许之前相关的中文材料: /post/719474…

classes with class modifiers

Dart 3 的第三个言语特性是类修饰符,与前两个支撑不同的是,这更像是一个高档用户功用,它首要是为了满意了 Dart 开发人员制作大型 API 或构建企业级应用时的需求。

现在是根据 constructedextendedimplemented 来完成处理,关键词有

类修饰符使 API 作者能够仅支撑一些特定的功用,而默许值坚持不变,例如:abstractbasefinalinterfacesealedmixin

只要base修饰符能够呈现在 mixin 声明之前,修饰符不适用于其他声明如 enumtypedefextension

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 …
}

例如要强制承继类或 mixin 的完成,就能够运用 base 修饰符。 base 不答应在其自己的库之外完成,这保证:

  • 每逢创立类的子类型的实例时,都会调用基类构造函数
  • 一切完成的私有成员都存在于子类型中
  • 类中新完成的成 员base不会损坏子类型,由于一切子类型都承继了新成员
// Library a.dart
base class Vehicle {
  void moveForward(int meters) { ... }
}
// Library b.dart
import 'a.dart';
var myCar = Vehicle();            // Can be constructed
base class Car extends Vehicle {  // Can be extended
    int passengers;
    // ...
}
base class MockVehicle implements Vehicle {  // ERROR: Cannot be implemented
    @override
    void moveForward { ... }
}

如果要创立一组已知的、可枚举的子类型,就能够运用修饰符 sealed ,sealed 答应在那些静态子类型上创立一个 switch 。

sealed class Vehicle { ... }
class Car extends Vehicle { }
class Truck implements Vehicle { }
class Bicycle extends Vehicle { }
// ...
var vehicle = Vehicle();  // ERROR: Cannot be instantiated
var vehicle = Car();      // Subclasses can be instantiated
// ...
// ERROR: The switch is missing the Bicycle subtype or a default case.
return switch (vehicle) {
  Car() => 'vroom',
  Truck() => 'VROOOOMM'
};

类修饰符存在一些添加限制,例如:

  • 运用 interface class ,能够界说 contract 给其他人去完成,但不能扩展接口类。
  • 运用 base class,能够保证类的一切子类型都承继自它,而不是完成它的接口,这保证私有方法在一切实例上都可用。
  • 运用 final class,能够封闭类型层次结构,以避免自己的库之外的任何子类。这样的优点是答应 API 一切者添加新成员,而不会呈现损坏 API 运用者更改的危险。

是不是没看明白?有关详细信息,能够参阅 dart.dev/language/cl…

展望未来

Dart 3 不仅仅是是在这些新功用上向前迈出了重要的一步,还为咱们供给了下一步的预览。

Dart language

Records, patterns 和 class modifiers 是十分庞大的新功用,因而它们的某些设计或许还需求改进,所以接下来还会有一些更小、更增量的功用更新,这些功用彻底不会中止,并且专注于在没有搬迁本钱的状况下提高开发人员的工作效率

现在正在探究的还有 primary constructors 和 inline classes 包装,别的之前讨论过的宏(也称为元编程)也在进行探究,由于元编程的规模和固有危险,现在正在采取一种更有用和彻底的方法进行探究,因而没有详细的时刻表能够共享,即使是最终确认的设计决策。

native interop

移动和桌面上的应用通常依赖于 native 渠道供给的大量 API,无论是通知、付出仍是获取手机位置等。

在之前 Flutter 中,这些是经过构建插件来访问的,这需求为 API 编写 Dart 代码和一堆特定于渠道的代码来供给完成。

现在已经支撑与运用 dart:ffi 直接和原生言语进行交互,咱们现在正在努力扩展它在Android 上的支撑,再次之前能够看 Java 和 Kotlin interop 以及 Objective-C 和 Swift interop 。

请检查新的 Google I/O 23 的 Android interop 视频。

编译为 WebAssembly——运用 native 代码定位 web

WebAssembly (缩写为 Wasm)作为跨一切浏览器的渠道的二进制指令格式,其可用性度一直在增长,Flutter 结构运用 Wasm 有一段时刻了,这便是咱们如何经过 Wasm 编译模块将用 C++ 编写的 SKIA 图形渲染引擎交给给浏览器的完成。

Flutter 也一直对运用 Wasm 来部署 Dart 代码很感兴趣,可是在此之前该完成被阻止了,与许多其他面向方针的言语一样,由于 Dart 需求运用废物收回。

在曩昔的一年里,Flutter 和 Wasm 生态体系中的多个团队协作,将新的 WasmGC 功用添加到 WebAssembly 规范中,现在在 Chromium 和 Firefox 浏览器中已经接近安稳。

将 Dart 编译为 Wasm 模块的工作有两个针对 Web 的高档方针:

  • 加载时刻: 咱们期望咱们能够运用 Wasm 交给部署有用负载,使浏览器能够更快地加载,然后缩短抵达用户能够与 Web 交互的时刻。
  • 性能:JavaScript 供给支撑的 Web 应用需求即时编译才干取得良好的性能,Wasm 模块更底层,更接近机器代码,因而咱们认为它们能够供给更高的性能、更少的卡顿和更共同的帧率。
  • 语义共同性:Dart 在咱们支撑的渠道之间坚持高度共同而自豪。可是,在 web 上有一些例外状况,例如 Dart web 现在在数字表示方法上有所不同,而运用 Wasm 模块,咱们能够将 web 视为具有与其他原生方针相似语义的“原生”渠道。

跟从 Dart3 的发布, Dart 到 Wasm 编译的第一个预览也一同发布,这是开始的 Flutter Web 重点支撑。尽管现在还早,后续还有许多工作要完成,但已经能够经过 flutter.dev/wasm 开始测验。