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

如何创建无返回值的Swift代码替换宏?当前实现失效求排查

问题分析与解决方案

这个宏完全可以实现,你遇到的错误核心原因是宏的类型定义不匹配:

你当前使用的是@freestanding(expression)(表达式宏),但你要生成的guard let self = self...是一条语句,并非表达式。编译器无法将语句当作表达式处理,导致宏的替换逻辑未被正确执行,self仍保持可选类型,因此触发了未解包的错误。

修正步骤

1. 修改宏的声明类型

将宏的声明从表达式类型改为独立语句类型:

@freestanding(statement)
public macro weakSelf() = #externalMacro(
    module: "MyMacroMacros",
    type: "SelfGuardMacro"
)

2. 调整宏的实现协议

将宏实现从ExpressionMacro改为FreestandingStatementMacro(专门处理独立语句的宏协议),并返回语句数组:

public struct SelfGuardMacro: FreestandingStatementMacro {
    public static func expansion(
        of node: some SwiftSyntax.FreestandingMacroExpansionSyntax,
        in context: some SwiftSyntaxMacros.MacroExpansionContext
    ) throws -> [StmtSyntax] {
        guard let stmt = try? StmtSyntax(stringLiteral: """
        guard let self = self else {
            assertionFailure()
            return
        }
        """) else {
            throw MacroExpansionError(message: "生成weak self guard语句失败")
        }
        return [stmt]
    }
}

3. 验证修正后的代码

此时你的MyClass代码将正常编译,因为宏会正确插入guard let self = self语句,后续代码中的self已被解包为非可选类型:

class MyClass {
    var closure: (() -> Void)!
    
    func function() {
        self.closure = { [weak self] in
            #weakSelf
            self.printString() // 不再报错
        }
    }
    
    func printString() {
        print("printing")
    }
}

扩展:支持传入返回值参数

针对有返回值的闭包,你可以扩展宏以支持自定义返回值参数,具体实现如下:

带参数的宏声明

@freestanding(statement)
public macro weakSelf(return: Any? = nil) = #externalMacro(
    module: "MyMacroMacros",
    type: "SelfGuardMacro"
)

处理参数的宏实现

public struct SelfGuardMacro: FreestandingStatementMacro {
    public static func expansion(
        of node: some SwiftSyntax.FreestandingMacroExpansionSyntax,
        in context: some SwiftSyntaxMacros.MacroExpansionContext
    ) throws -> [StmtSyntax] {
        // 解析传入的return参数
        let returnExpr = node.argumentList.first {
            $0.label?.text == "return"
        }?.expression
        
        // 根据参数生成对应的guard语句
        let guardCode: String
        if let expr = returnExpr {
            guardCode = """
            guard let self = self else {
                assertionFailure()
                return \(expr)
            }
            """
        } else {
            guardCode = """
            guard let self = self else {
                assertionFailure()
                return
            }
            """
        }
        
        guard let stmt = try? StmtSyntax(stringLiteral: guardCode) else {
            throw MacroExpansionError(message: "生成weak self guard语句失败")
        }
        return [stmt]
    }
}

用法示例

在有返回值的闭包中使用:

let stringClosure: () -> String = { [weak self] in
    #weakSelf(return: "默认值")
    return self.someProperty // self已解包,可直接访问
}

内容的提问来源于stack exchange,提问作者Nikita

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 09:25:11