如何实现Swift闭包的自定义宏附加?寻求适配的宏类型
Swift闭包宏实现方案解答
已实现的函数宏效果
你已经成功实现了附加到函数声明的宏,将带注解的函数:
@DoThing func foo() { }
转换为:
func foo() { thing() }
需求目标
希望实现类似@MainActor在闭包中的用法,将:
Task { @DoThing [capture] in }
转换为:
Task { [capture] in thing() }
并且支持所有闭包类型(包括带参数的闭包),同时想了解是否存在可直接查看完整闭包声明的现有宏类型。
解决方案
不存在专门用于“查看完整闭包声明”的现成宏类型,但可以通过附加到表达式的属性宏结合SwiftSyntax语法解析来实现需求,具体步骤如下:
1. 定义支持闭包的宏
需要让你的DoThing宏同时支持函数声明和闭包表达式,通过指定宏的attachmentPoints包含.expression(闭包属于表达式类型),并实现对应的表达式展开逻辑:
import SwiftSyntax import SwiftSyntaxMacros public struct DoThingMacro: AttachedMacro { // 原有函数宏的展开逻辑 public static func expansion( of node: AttributeSyntax, attachedTo declaration: some DeclGroupSyntax, providingExtensionsOf type: some TypeSyntaxProtocol, conformingTo protocols: [TypeSyntax], in context: some MacroExpansionContext ) throws -> [ExtensionDeclSyntax] { guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else { throw MacroError.unsupportedDeclaration } var modifiedFunc = funcDecl let thingStmt = SyntaxFactory.makeExprStmt( expression: IdentifierExprSyntax(identifier: "thing") .withTrailingTrivia(.space) .withTrailingSyntax(SyntaxFactory.makeParenExpr()) ) modifiedFunc.body?.statements.insert(thingStmt, at: 0) return [ExtensionDeclSyntax( extendedType: funcDecl.signature.returnType ?? TypeSyntax(IdentifierTypeSyntax(name: "Void")), members: MemberDeclSyntax(modifiedFunc) )] } // 新增闭包表达式的展开逻辑 public static func expansion( of node: AttributeSyntax, attachedTo expression: some ExprSyntax, in context: some MacroExpansionContext ) throws -> ExprSyntax { guard let closureExpr = expression.as(ClosureExprSyntax.self) else { throw MacroError.unsupportedExpression } // 创建要插入的thing()语句 let thingStmt = SyntaxFactory.makeExprStmt( expression: IdentifierExprSyntax(identifier: "thing") .withTrailingTrivia(.space) .withTrailingSyntax(SyntaxFactory.makeParenExpr()) ) // 将新语句插入到闭包语句体开头 var modifiedStatements = closureExpr.statements modifiedStatements.insert(thingStmt, at: 0) // 构建新闭包:移除@DoThing注解,保留原有捕获列表、参数、语句 let newClosure = closureExpr .withoutAttributes() .withStatements(modifiedStatements) return ExprSyntax(newClosure) } // 指定宏可附加到函数声明和表达式(闭包) public static var attachmentPoints: [AttachmentPoint] { [.declaration(.function), .expression] } } enum MacroError: Error { case unsupportedDeclaration case unsupportedExpression }
2. 处理各类闭包场景
通过ClosureExprSyntax可以完整解析闭包的所有组成部分:
- 捕获列表:
closureExpr.captureClause - 参数签名:
closureExpr.signature - 语句体:
closureExpr.statements
这意味着不管闭包带捕获列表、参数还是复杂逻辑,都能正确处理。例如:
原闭包代码:
let closure = { @DoThing [weak self, unowned delegate] (input: String) -> Bool in guard let self else { return false } return self.process(input) }
转换后会变为:
let closure = { [weak self, unowned delegate] (input: String) -> Bool in thing() guard let self else { return false } return self.process(input) }
总结
没有现成的宏类型直接提供“完整闭包声明查看”的能力,但通过自定义AttachedMacro并指定.expression附加点,结合SwiftSyntax的语法树解析,就能完全获取闭包的所有结构信息,实现你需要的宏效果。
内容的提问来源于stack exchange,提问作者Matt Braniff
相关产品推荐
相关产品推荐

