参阅链接:medium.com/dartlang/da…

跟随 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;
    }
    

Dart 3.3 发布:扩展类型、JavaScript Interop 等

  • 为现有类型供给不同的接口不通明的扩展类型(不是 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'.
      ];
    }
    

Dart 3.3 发布:扩展类型、JavaScript Interop 等

另外需求注意,扩展类型是编译时包装构造,在运转时绝对没有扩展类型的踪影,任何类型查询或相似的运转时操作都适用于表明类型,在任何情况下,扩展类型的表明类型都不是其子类型,因而在需求扩展类型的情况下表明类型不能交换运用。

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

更多可见:dart.dev/interop/js-…