Swift 5.9 引入宏支持
在 WWDC 2023 上,苹果发布了 Swift 5.9 的测试版,该版本通过支持在编译时生成代码的宏功能,显著扩展了语言的能力。
宏的作用与特点
宏旨在通过引入类似于语言原语的构造来扩展编程语言的能力,并尽可能减少样板代码。Swift 宏在抽象语法树(AST)级别工作,允许在编译时生成代码并将其反馈给编译器。Swift 宏与 C/C++ 宏不同,后者仅进行某种专门的字符串替换,而 Swift 宏更类似于 Rust 或 Scala 中的宏,但有其独特之处。
宏将一个 AST 转换为另一个 AST,且不依赖或改变任何外部状态。
宏的类型
Swift 有两种类型的宏:
- 独立宏(Freestanding Macros):独立出现,不附加到声明中,语法上以
#开头。 - 附加宏(Attached Macros):修改紧随其后的程序实体的声明,语法上以
@开头。
宏的扩展过程
Swift 编译器在扩展宏时,首先构建程序的 AST,然后将 AST 的部分发送给宏实现,宏实现使用这些部分构建其扩展形式。编译器最终使用扩展后的 AST 替换宏调用,并确保生成的代码仍然有效。宏可以嵌套在其他宏中,此时外部宏首先展开,并可以修改内部宏。
宏的声明与实现
与其他语言功能不同,Swift 宏需要单独声明和实现。宏声明使用 macro 关键字,定义其在代码中的调用位置和生成的代码类型。例如,标准库宏 @OptionSet 的声明如下:
@attached(member)
@attached(conformance)
public macro OptionSet<RawType>() =
#externalMacro(module: "SwiftMacros", type: "OptionSetMacro")该宏声明指定了宏实现的位置和类型,例如在 "SwiftMacros" 模块中的 "OptionSetMacro" 类型。
宏的实现
实现宏的过程相对复杂,宏实现为一个库,提供类型(如 struct),并属于 Xcode 项目中的一个独立目标。使用 Swift Package Manager 可以轻松创建宏模板:
swift package init --type macro宏实现严格依赖于程序的 AST,必须提供一个 expansion(of:in:) 方法,接收 AST 和宏上下文作为参数,并返回一个 ExprSyntax。例如:
public struct FourCharacterCode: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
...
}宏的调试
如果从宏的 expansion 实现中抛出异常,它将在宏调用处被视为编译错误,这使得宏调试比其他语言更简单。
实验 Swift 宏
如果你想尝试 Swift 宏,可以下载 Xcode 15 测试版或在 Xcode 14 中安装最新的 Swift 工具链。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。