You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:55:15