宏 (实验性)
Dart 宏系统 是一项重大的新语言特性,目前正在开发中,它为 Dart 语言添加了对 静态元编程 的支持。
Dart 宏是用户定义的一段代码,它以其他代码作为参数,并在实时运行时对代码进行操作,以创建、修改或添加声明。
你可以将宏系统分成两部分:使用宏和编写宏。本页面涵盖了这两部分(处于较高层级,因为该功能仍然处于预览阶段),以下各节将进行介绍。
JsonCodable
宏:一个你可以立即尝试(在实验性标志下)的现成宏,它为 Dart 中常见的繁琐 JSON 序列化和反序列化问题提供了一个无缝解决方案。宏特性概述:我们为什么要在 Dart 中添加宏,用例的动机,与现有代码生成解决方案相比的优势,以及编写宏在该功能完成后将如何运作的粗略概述。
JsonCodable
宏
#JsonCodable
宏将用户定义的 Dart 类编码和解码为类型为 Map<String, Object?>
的 JSON 地图。它生成两个成员,一个 toJson
序列化方法和一个 fromJson
反序列化构造函数。
设置实验
#切换到 Dart dev 频道 或 Flutter master 频道。
运行
dart --version
并确保你拥有 Dart 版本3.5.0-152
或更高版本。在你的 pubspec 中编辑 SDK 约束 以要求 Dart 版本:
sdk: ^3.5.0-152
。添加包
json
到dependencies
:dart pub add json
。启用实验性标志 在你的包的
analysis_options.yaml
文件中。在你的项目的根目录中yamlanalyzer: enable-experiment: - macros
在你要使用它的文件中导入包
dartimport 'package:json/json.dart';
使用实验性标志运行你的项目
dart run --enable-experiment=macros bin/my_app.dart
使用宏
#要使用 JsonCodable
宏,将注释附加到你想要序列化的类上
import 'package:json/json.dart';
@JsonCodable() // Macro annotation.
class User {
final int? age;
final String name;
final String username;
}
宏会反省 User
类,并使用 User
类的字段推导出 fromJson
和 toJson
的实现。
因此,无需自己定义,toJson
和 fromJson
现在可用于注释类的对象
void main() {
// Given some arbitrary JSON:
var userJson = {
'age': 5,
'name': 'Roger',
'username': 'roger1337'
};
// Use the generated members:
var user = User.fromJson(userJson);
print(user);
print(user.toJson());
}
查看生成的代码
#有时查看生成的代码有助于更好地理解宏的工作原理,或检查其提供的详细信息。
单击你的 IDE(在 VSCode 中支持)中注释下方显示的“转到增强”链接,以查看宏如何生成 toJson
和 fromJson
。
如果你在注释的类中更改任何内容,可以观察到生成的增强会与你的应用程序代码同步实时调整
触发自定义诊断
#JsonCodable
宏具有内置的诊断,这些诊断就像语言本身的诊断一样发出。例如,如果你尝试在应用宏的地方手动声明 toJson
方法,分析器将发出错误
@JsonCodable()
class HasToJson {
void toJson() {}
// Error: Cannot generate a toJson method due to this existing one.
}
你可以在 JsonCodable
的定义 中搜索“DiagnosticMessage
”,以了解宏将引发的其他错误。例如,扩展一个不是可序列化的类,或者如果字段名称与给定 JSON 中的键名称不完全匹配。
宏语言特性
#Dart 宏是一种静态元编程或代码生成解决方案。与运行时代码生成解决方案(例如 build_runner)不同,宏完全集成到 Dart 语言中,并由 Dart 工具在后台自动执行。这使得宏比依赖于辅助工具效率高得多
- 无需额外运行;宏会在你编写代码时实时构建。
- 没有重复工作或持续的重新编译会影响性能;所有构建和代码生成都在编译器中直接自动完成。
- 不写入磁盘,因此没有部分文件或指向生成的引用的指针;宏直接增强现有类。
- 没有令人困惑/模糊的测试;自定义诊断像分析器中的任何其他消息一样发出,直接在 IDE 中。
而且效率更高,而且比你自己手动编写这些问题的解决方案错误率低得多。
用例
#宏提供可重用的机制来解决以繁琐的样板代码为特征的模式,并且通常需要遍历类的字段。我们希望将来使用宏解决的一些常见示例是
JSON 序列化。 用于序列化 JSON 的额外工具,例如 json_serializable 包,效率并不如预期那么高。
JsonCodable
宏提供了一种更简洁的方法来生成序列化代码;立即尝试。数据类。 Dart 最需要的 功能是数据类,它自动提供构造函数,以及对每个字段的
==
、hashCode
和copyWith()
方法的实现。使用宏实现解决方案意味着用户可以根据自己的需要自定义数据类。冗长的 Flutter 模式。 一个例子是将复杂的
build
方法分解成较小的 widget 类集合。这对于性能更好,并且使代码更易于维护。不幸的是,编写所有这些较小的类需要大量的样板代码,这会让用户望而却步。宏有可能提供一种解决方案,该解决方案会遍历复杂的build
方法来生成较小的 widget 类,从而大大提高 Flutter 代码的生产力和质量。你可以查看 Flutter 团队在这方面的一个探索 提案。
宏的工作原理
#要创建宏,您可以编写类似于类的宏声明,使用 macro
关键字。宏声明还必须包含一个 implements
子句,用于定义宏可以应用于哪个接口。
例如,适用于类并向类添加新声明的宏将实现 ClassDeclarationsMacro
接口
macro class MyMacro implements ClassDeclarationsMacro {
const MyMacro();
// ...
}
虽然该功能仍在开发中,但您可以在 源代码 中找到宏接口的完整列表。
上面示例中的 MyMacro
构造函数对应于您将用于将宏应用于声明的注释。语法与 Dart 现有的元数据注释语法相同
@MyMacro()
class A {}
在宏声明的正文中,您定义宏要 生成 的代码,以及宏要发出的任何 诊断。
从非常高的层次上讲,编写宏本质上是通过使用构建器方法将声明的属性与这些属性上的标识符拼凑在一起。宏通过对程序进行深入的 内省 收集这些信息。
宏仍在开发中,因此目前只能提供这些细节。如果您对此感到好奇,或者想在实验性标志后面尝试一下,最好的指导是查看现有宏的实现
时间线
#宏的稳定发布日期目前未知。这是由于其实现的复杂性。
宏通过对它们所应用的程序进行深入的 内省 来工作。宏最终可能会遍历程序的远端部分,以收集有关它正在增强的声明的属性和类型注释的必要信息。
考虑到它们在大型代码库中的应用,多个宏可以在不同的地方持续地内省和增强基础代码,因此 排序 和 阶段 执行的设计尤其具有挑战性,需要仔细考虑。
我们正在努力在今年年底(2024 年)发布 JsonCodable
宏的稳定版本,并在明年年初(2025 年)发布完整语言特性的稳定版本(即,编写自己的宏)。
除非另有说明,否则本网站上的文档反映了 Dart 3.5.3。页面最后更新于 2024-10-22。 查看源代码 或 报告问题.