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

如何用Swift宏从函数参数初始化带关联值的枚举?

从FunctionDeclSyntax提取参数生成Mock枚举关联值与调用记录

核心思路

解决这个问题的关键是利用SwiftSyntax的FunctionDeclSyntax和ParameterSyntax相关API,精准提取函数的内部参数名与类型,分别用于生成枚举关联值的定义,以及calls.append调用里的参数传递逻辑。

分步实现

  1. 获取函数参数列表
    从FunctionDeclSyntax实例中,通过signature.parameterClause.parameters拿到所有参数的ParameterSyntax数组,每个实例包含了参数的外部名、内部名和类型信息。

  2. 提取参数的内部名与类型
    对于每个ParameterSyntax:

  • 内部名取secondName(这是方法实现中实际可用的变量名)
  • 参数类型直接取type属性

比如处理func myFunction(_ name: String, count: Int)时,会得到两组数据:

  • 第一个参数:内部名name,类型String
  • 第二个参数:内部名count,类型Int
  1. 生成枚举Case的关联值定义
    将提取到的参数名和类型拼接成枚举case的关联值格式,示例代码如下:
func generateCallEnumCase(from function: FunctionDeclSyntax) -> EnumCaseElementSyntax {
    let parameterList = function.signature.parameterClause.parameters
    
    let associatedValues = parameterList.compactMap { param in
        guard let paramName = param.secondName?.text, let paramType = param.type.as(IdentifierTypeSyntax.self) else {
            return nil
        }
        return TupleTypeElementSyntax(
            name: TokenSyntax.identifier(paramName),
            colon: .colonToken(),
            type: paramType
        )
    }
    
    return EnumCaseElementSyntax(
        name: TokenSyntax.identifier(function.name.text),
        associatedValue: TupleTypeSyntax(elements: TupleTypeElementListSyntax(associatedValues))
    )
}

这段代码会为上面的示例函数生成:case myFunction(name: String, count: Int)

  1. 生成calls.append的调用语句
    复用参数的内部名,拼接成调用枚举case的代码,示例代码如下:
func generateCallAppendStatement(from function: FunctionDeclSyntax) -> FunctionCallExprSyntax {
    let parameterList = function.signature.parameterClause.parameters
    
    let callArguments = parameterList.compactMap { param in
        guard let paramName = param.secondName?.text else {
            return nil
        }
        return FunctionCallArgumentSyntax(
            label: TokenSyntax.identifier(paramName),
            colon: .colonToken(),
            expression: IdentifierExprSyntax(identifier: TokenSyntax.identifier(paramName))
        )
    }
    
    return FunctionCallExprSyntax(
        calledExpression: MemberAccessExprSyntax(
            base: IdentifierExprSyntax(identifier: TokenSyntax.identifier("calls")),
            name: TokenSyntax.identifier("append")
        ),
        leftParen: .leftParenToken(),
        arguments: FunctionCallArgumentListSyntax(callArguments),
        rightParen: .rightParenToken()
    )
}

这段代码会为示例函数生成:calls.append(.myFunction(name: name, count: count))

整合到Mock类生成流程

遍历ProtocolDeclSyntax的成员时,筛选出所有FunctionDeclSyntax实例,分别用上述方法生成枚举Case和方法内的调用语句,再将这些片段组合成完整的Mock类代码即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:30:20