如何通过Swift宏实现枚举案例跨枚举复制?AttributeSyntax使用疑问
Swift宏实现枚举案例代理的解决方案
核心逻辑
要实现@CaseProxy(ChildEnum.self)这种枚举案例复制的宏,核心是两步:从属性注解里解析出目标枚举类型,再通过Swift的语义分析能力拿到该枚举的所有案例,最后把这些案例代码插入到父枚举中。
具体实现步骤
1. 从AttributeSyntax提取目标枚举类型
先写个工具函数,把@CaseProxy(ChildEnum.self)里的ChildEnum类型提取出来:
func extractTargetEnum(from attribute: AttributeSyntax) -> TypeSyntax? { guard let args = attribute.arguments?.as(LabeledExprListSyntax.self), let firstArg = args.first?.expression.as(MemberAccessExprSyntax.self), let enumName = firstArg.base.as(IdentifierExprSyntax.self)?.identifier.text, firstArg.name.text == "self" else { return nil } return TypeSyntax("\(raw: enumName)") }
2. 通过语义模型获取枚举的案例成员
在宏的扩展方法里,利用SemanticModel查询目标枚举的完整声明,进而提取所有案例:
func expand( attribute: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { // 拿到目标枚举的类型语法 guard let targetType = extractTargetEnum(from: attribute), // 解析类型对应的符号 let typeSymbol = context.semanticModel.resolveType(targetType)?.symbol, // 转成枚举声明节点 let enumDecl = typeSymbol.declaration.as(EnumDeclSyntax.self) else { throw MacroError.failedToResolveEnum } // 遍历枚举成员,筛选出所有案例 let caseElements = enumDecl.memberBlock.members .compactMap { $0.decl.as(EnumCaseDeclSyntax.self) } .flatMap { $0.elements } // 生成父枚举需要的case声明 return caseElements.map { element in DeclSyntax("case \(element.name)") } }
3. 定义宏和错误类型
先声明自定义错误类型:
enum MacroError: Error { case failedToResolveEnum }
再定义宏的公开接口:
@freestanding(declaration, names: arbitrary) public macro CaseProxy(_ enumType: Any.Type) = #externalMacro(module: "YourMacroModule", type: "CaseProxyMacro")
记得把YourMacroModule替换成你的宏所在的模块名称。
使用示例
enum ChildEnum { case childA case childB } @CaseProxy(ChildEnum.self) enum ParentEnum { // 宏会自动生成以下代码: // case childA // case childB }
内容的提问来源于stack exchange,提问作者JaSHin
相关产品推荐
相关产品推荐

