Swift 5.9 为语言带来宏扩展能力

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 工具链。

阅读 27
0 条评论