Dart宏:提升开发抽象层次


官方花了很多年时间来设计Dart宏系统。为了提升Dart的开发体验,宏提供了一种类似于代码生成的元编程解决方案。这种解决方案是内置于Dart语言中的,旨在为开发人员提供最高的性能、效率和生产力。现在,我来为为您展示这一体验!


长期以来,Dart开发人员的一个痛点是将JSON数据序列化和反序列化的简单但冗长的模式。由于性能原因,Dart不支持运行时反射,因此创建一个可重用且功能足够强大的解决方案是一个挑战。作为替代方案,我们依赖于像 JsonSerializable 这样的代码生成解决方案。这些解决方案依赖于在代码本身运行之前运行的外部工具,从而使开发人员的体验变得更加复杂。


Dart3.4更新,官方宣布推出一种全新的JSON序列化和反序列化方法: JsonCodable 宏。


宏是一种代码类型,它在编译时通过内省其他代码来生成更多代码。例如,这里是一个使用了JsonCodable宏的Dart类Vehicle:

@JsonCodable()
class Vehicle {
  final String description;
  final int wheels;
  Vehicle(this.description, this.wheels);
}
void main() {
  final jsonString = Vehicle('bicycle', 2).toJson();
  print('Vehicle serialized: $jsonString');
}

工作原理

那么它是如何工作的呢? toJson() 方法(以及与其对应的 fromJson() 构造函数)是从哪里来的呢?这是一个实验性的实现,旨在简化开发者的体验。当Dart编译器看到 @JsonCodable() 注释时,它会立即在实时查找JsonCodable宏的定义,并开始执行它。

这使得宏能够:

  1. 创建一个新的“augmentation class”;一种新的语言结构,它允许向现有类中添加新的声明。

  2. 阅读开发者对 Vehicle 类的定义,以确定它有两个字段, description 和 wheels 。

  3. 在扩展类中添加一个新的 toJson 方法签名。

  4. 填充 toJson 方法的主体部分,以处理descriptionwheels字段的序列化操作。


所有这些操作都是实时完成的。这种集成体验支持我们现有的开发工作流程,比如热重载,如下面的屏幕截图所示:


长期宏观目标

最终目标是让社区能够创建自己的宏。这提高了Dart编程的抽象级别。例如数据类,它是Dart语言中最受投票支持的功能。官方考虑在Dart中添加内置的数据类支持,但了解到对于此类构造应该支持哪些功能以制定自己的标准,各方意见分歧较大。字段应该被隐藏吗?它应该支持equals吗?又或者应该支持其他什么功能?得出的结论是,支持宏系统才是更好的做法。社区可以创建自己的各种抽象,从而实现更可扩展的实验和更多样化的功能。


设计和实现这样一个强大的宏系统是一个重大的工程。官方决心以一种不会对核心Dart开发人员的关键用例(如代码辅助、代码补全、代码分析和热重载)产生负面性能影响的方式来实现它。考虑到这一点,将采取分阶段的方法:

  • 在Dart3.4的发布中,提供了一个名为 JsonCodable 的单个宏的预览,以便用户开始熟悉使用宏的开发体验。

  • 如果这个宏的部署顺利,那么在后续版本中将JSON宏升级为稳定版本。

  • 同时,正在致力于完成底层宏系统的设计和实现工作。一旦对其性能和稳定性感到满意,最终目标将是让Dart开发人员社区能够定义自己的宏。


要完成这些阶段任重道远,还有很多工作要做,希望Flutter&Dart越来越好,愿世界和平!