跟随 Flutter 3.19 发布的还有 Dart 3.3 ,Dart 3.3 首要包含扩展类型增强,功用优化和 native 代码交互推动,例如本次改善的JavaScript Interop 模型就引入了类型安全,所以这一切都为 WebAssembly 支撑铺平了道路。
在《Flutter 2024 路线规划里》 ,Web 渠道上未来 CanvasKit 将成为默许烘托,所以未来 Dart 在 Web 上肯定是 Wasm Native 的路线。
扩展类型
扩展类型是一种编译时笼统,它用不同的纯静态接口来 “Wrapper” 现有类型,一起它们也是 Dart 和静态 JS 互操作的首要完成根底,由于它们能够轻松修正现有类型的接口(关于任何类型的彼此调用都至关重要),而不会发生实际 Wrapper 的本钱。
extension type E(int i) {
// Define set of operations.
}
扩展类型引入了类型的零本钱 wrappers,运用它们来优化功用敏感的代码,尤其是在与 native 渠道交互时,扩展类型供给了具有特定成员自界说类型的便利性,一起消除了典型的 wrappers 分配开销。
extension type Wrapper(int i) {
void showValue() {
print('my value is $i');
}
}
void main() {
final wrapper = Wrapper(42);
wrapper.showValue(); // Prints 'my value is 42'
}
上面的例子完成了一个 Wrapper
扩展类型,但将其用作一般的 Dart 类型,在实际运用里,开发者能够实例化它并调用函数。
这儿的首要差异在于 Dart 将其编译为一般 Dart int
类型,扩展类型答应创立具有唯一的成员类型,而无需分配典型 wrappers 类型的直接本钱,例如以下例子包装了对应的 int
类型以创立仅答应对 ID 号有意义的操作的扩展类型。
extension type IdNumber(int id) {
// Wraps the 'int' type's '<' operator:
operator <(IdNumber other) => id < other.id;
// Doesn't declare the '+' operator, for example,
// because addition does not make sense for ID numbers.
}
void main() {
// Without the discipline of an extension type,
// 'int' exposes ID numbers to unsafe operations:
int myUnsafeId = 42424242;
myUnsafeId = myUnsafeId + 10; // This works, but shouldn't be allowed for IDs.
var safeId = IdNumber(42424242);
safeId + 10; // Compile-time error: No '+' operator.
myUnsafeId = safeId; // Compile-time error: Wrong type.
myUnsafeId = safeId as int; // OK: Run-time cast to representation type.
safeId < IdNumber(42424241); // OK: Uses wrapped '<' operator.
}
因而,尽管 extension members 功用(Dart 2.7 开端)答应向现有类型添加函数和特点,但扩展类型功用也能够执行相同的操作,而且还答应界说隐藏底层表明的新 API。
这关于与 native code 的彼此调用特别有用。能够直接运用原生类型,无需创立 Wrapper 和相关直接的本钱,一起依然供给干净的生产 Dart API。
扩展类型与 Wrapper 具有相同的用途,但不需求创立额外的运转时目标,当开发者需求包装大量目标时,Wrapper 这个行为可能会变得贵重,由于扩展类型仅是静态的而且在运转时编译,因而它们本质上是零本钱。
扩展办法(也称为“扩展”)是相似于扩展类型的静态笼统。可是扩展办法是直接向其根底类型的每个实例添加功用;扩展类型不同,扩展类型的接口仅适用于静态类型为该扩展类型的表达式。
默许情况下它们与其根底类型的接口不同。
扩展类型有两个同样有用但本质上不同的中心用例:
-
为现有类型供给扩展接口,当扩展类型完成其表明类型时,一般能够以为它是“通明的”,由于它答应扩展类型“看到”底层类型。
通明扩展类型能够调用表明类型的一切成员(未重新声明的),以及它界说的任何辅佐成员,这将为现有类型创立一个新的扩展接口,新接口可用于静态类型为扩展类型的表达式,例如如下代码里,
v1.i
能够正常调用,可是 int 相似的v2
不能够调用v2.i
:extension type NumberT(int value) implements int { // Doesn't explicitly declare any members of 'int'. NumberT get i => this; } void main () { // All OK: Transparency allows invoking `int` members on the extension type: var v1 = NumberT(1); // v1 type: NumberT int v2 = NumberT(2); // v2 type: int var v3 = v1.i - v1; // v3 type: int var v4 = v2 + v1; // v4 type: int var v5 = 2 + v1; // v5 type: int // Error: Extension type interface is not available to representation type v2.i; }
-
为现有类型供给不同的接口,不通明的扩展类型(不是
implement
其表明类型)被静态地视为全新类型,与其表明类型不同,所以无法将其分配给其表明类型,而且它不会揭露其表明类型的成员,例如NumberE
不能为 int ,而且 :extension type NumberE(int value) { NumberE operator +(NumberE other) => NumberE(value + other.value); NumberE get next => NumberE(value + 1); bool isValid() => !value.isNegative; } void testE() { var num1 = NumberE(1); int num2 = NumberE(2); // Error: Can't assign 'NumberE' to 'int'. num1.isValid(); // OK: Extension member invocation. num1.isNegative(); // Error: 'NumberE' does not define 'int' member 'isNegative'. var sum1 = num1 + num1; // OK: 'NumberE' defines '+'. var diff1 = num1 - num1; // Error: 'NumberE' does not define 'int' member '-'. var diff2 = num1.value - 2; // OK: Can access representation object with reference. var sum2 = num1 + 2; // Error: Can't assign 'int' to parameter type 'NumberE'. List<NumberE> numbers = [ NumberE(1), num1.next, // OK: 'i' getter returns type 'NumberE'. 1, // Error: Can't assign 'int' element to list type 'NumberE'. ]; }
另外需求注意,扩展类型是编译时包装构造,在运转时绝对没有扩展类型的踪影,任何类型查询或相似的运转时操作都适用于表明类型,在任何情况下,扩展类型的表明类型都不是其子类型,因而在需求扩展类型的情况下表明类型不能交换运用。
JavaScript Interop
Dart 3.3 引入了一种与 JavaScript 和 Web 彼此调用的新模型,它从一组用于与 JavaScript 交互的新 API 开端:dart:js_interop 。
现在,Dart 开发人员能够拜访类型化 API 来与 JavaScript 交互,该 API 通过静态强制明确界说了两种言语之间的边界,在编译之前消除了许多问题。
除了用于拜访 JavaScript 代码的新 API 之外,Dart 现在还包含一个新模型,用于运用扩展类型在 Dart 中表明 JavaScript 类型,如下代码就是前面拓展类型的实际运用实例:
import 'dart:js_interop';
/// Represents the `console` browser API.
extension type MyConsole(JSObject _) implements JSObject {
external void log(JSAny? value);
external void debug(JSAny? value);
external void info(JSAny? value);
external void warn(JSAny? value);
}
根据扩展类型的语法比扩展成员答应更多的表达和健全性。这简化了 Dart 中 JavaScript API 的运用,更多详细信息能够查看:dart.dev/interop/js-… 。
改善 browser libraries
从 1.0 版别开端,Dart SDK 就包含了一套全面的 browser libraries,其间包含中心 dart:html 库以及 SVG、WebGL 等库。
改善后的 JavaScript 调用模型供给了重新构想这些库的时机,未来 browser libraries 支撑将集中在 package:web上,这简化了版别操控、加速了更新并与MDN资源保持一致,这一系列的改善推动了将 Dart 编译为 WebAssembly。
从今天开端,开启 WebAssembly 的未来
Dart 3.3 为WebAssembly 的 Web 运用奠定根底,尽管 Flutter Web 中的 WebAssembly 支撑仍处于试验阶段,可是这关于 Dart 和 Flutter 是明显的方向。
要运用 WebAssembly 在 Web 上运转 Flutter 运用,需求运用新的 JavaScript Interop 机制和 package:web
,旧版 JavaScript 和 browser libraries 保持不变,并支撑编译为 JavaScript 代码。可是,假如编译为 WebAssembly 需求迁移,例如:
import 'dart:html' as html; // Remove
import 'package:web/web.dart' as web; // Add
dependencies:
web: ^0.5.0