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

如何通过Swift宏为枚举新增case并添加默认初始化方法?

Swift宏为枚举新增case及初始化器时编译失败的修复方案

问题场景

我尝试实现一个Swift宏@AddEnumCase,功能是给枚举自动添加developer case,同时生成自定义init(rawValue:)初始化器,将未匹配的原始值默认映射到developer。

原枚举代码:

@AddEnumCase
enum Employee: String {
   case manager
}

期望展开后的代码:

enum Employee: String {
  case manager
  case developer 
  init(rawValue: String) {
    switch rawValue {
    case Self.manager.rawValue: 
      self = .manager
    default: 
      self = .developer
    }
  }
}

编写的宏代码在main.swift为空时测试通过,但在main.swift中使用该宏时,出现编译错误:Command SwiftCompile failed with a nonzero exit code。宏代码如下:

public struct AddEnumCase: MemberMacro {
    
    public static func expansion(of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] {
        
        guard let enumDecl = declaration.as(EnumDeclSyntax.self) else { return [] }
        
        guard let inheritanceType = enumDecl.inheritanceClause?.inheritedTypes.first?.type else { return [] }
        
        let cases = enumDecl.memberBlock.members.compactMap { $0.decl.as(EnumCaseDeclSyntax.self)?.elements }
        
        let newElement = try EnumCaseDeclSyntax("case developer")
        
        let initializer = try InitializerDeclSyntax("init(rawValue: \(inheritanceType.trimmed))") {
          try SwitchExprSyntax("switch rawValue") {
           for name in cases {
             SwitchCaseSyntax("""
               case Self.\(raw: name).rawValue:
                 self = .\(raw: name)
               """)
              }
              SwitchCaseSyntax("""
               default:
                 self = .developer
               """)
              }
           }
        return [DeclSyntax(newElement), DeclSyntax(initializer)]
    }
}

@attached(member, names: arbitrary)
public macro AddEnumCase() = #externalMacro(module: "MyMacros", type: "AddEnumCase")

在main.swift中使用以下代码时构建失败:

@AddEnumCase
enum Employee: String {
   case Manager
}

错误原因分析

  1. 枚举case遍历逻辑错误:cases变量是[EnumCaseElementListSyntax]类型(数组嵌套数组),直接遍历会导致每个name是枚举元素列表而非单个元素,生成的代码存在语法错误。
  2. SwitchCase语法构建不规范:直接通过字符串插值生成SwitchCaseSyntax时,没有正确处理枚举元素的语法结构,且缺少必要的缩进和代码块包裹。
  3. 初始化器语法不完整:原代码中sitch语句缺少闭合大括号,导致生成的代码语法不完整。

修复后的宏代码

import SwiftSyntax
import SwiftSyntaxMacros

public struct AddEnumCase: MemberMacro {
    public static func expansion(of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext) throws -> [DeclSyntax] {
        guard let enumDecl = declaration.as(EnumDeclSyntax.self) else {
            return []
        }
        
        guard let inheritanceType = enumDecl.inheritanceClause?.inheritedTypes.first?.type else {
            return []
        }
        
        // 展平枚举case元素,获取单个枚举元素对象
        let enumElements = enumDecl.memberBlock.members
            .compactMap { $0.decl.as(EnumCaseDeclSyntax.self) }
            .flatMap { $0.elements }
        
        // 构建新增的developer case
        let newCase = EnumCaseDeclSyntax {
            EnumCaseElementSyntax(identifier: .identifier("developer"))
        }
        
        // 构建自定义初始化器
        let initializer = try InitializerDeclSyntax("init(rawValue: \(inheritanceType.trimmed))") {
            // 构建switch匹配语句
            SwitchExprSyntax(expression: IdentifierExprSyntax(identifier: .identifier("rawValue"))) {
                // 为每个原有枚举case生成匹配分支
                for element in enumElements {
                    SwitchCaseSyntax(
                        label: .case(
                            CaseItemSyntax(
                                pattern: ExprPatternSyntax(
                                    expression: MemberAccessExprSyntax(
                                        base: MemberAccessExprSyntax(base: TypeExprSyntax(type: enumDecl.name), name: element.name),
                                        name: .identifier("rawValue")
                                    )
                                )
                            )
                        ),
                        statements: CodeBlockItemListSyntax {
                            CodeBlockItemSyntax(
                                item: .stmt(
                                    AssignExprSyntax(
                                        leftHandSide: ExprSyntax(IdentifierExprSyntax(identifier: .identifier("self"))),
                                        rightHandSide: ExprSyntax(MemberAccessExprSyntax(base: nil, name: element.name))
                                    )
                                )
                            )
                        }
                    )
                }
                // 默认分支,匹配失败时赋值为developer
                SwitchCaseSyntax(
                    label: .default,
                    statements: CodeBlockItemListSyntax {
                        CodeBlockItemSyntax(
                            item: .stmt(
                                AssignExprSyntax(
                                    leftHandSide: ExprSyntax(IdentifierExprSyntax(identifier: .identifier("self"))),
                                    rightHandSide: ExprSyntax(MemberAccessExprSyntax(base: nil, name: .identifier("developer")))
                                )
                            )
                        }
                    )
                )
            }
        }
        
        return [DeclSyntax(newCase), DeclSyntax(initializer)]
    }
}

@attached(member, names: arbitrary)
public macro AddEnumCase() = #externalMacro(module: "MyMacros", type: "AddEnumCase")

验证说明

修复后的宏会生成完全符合语法规范的代码,以Employee枚举为例,展开结果与预期完全一致。此时在main.swift中使用该宏,编译不会再出现错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:35:31