Swift动态值Accessor Macro:如何实现关联存储属性的GetSetMacro
Swift Accessor宏GetSetMacro实现问题
我想编写一个名为GetSetMacro的Swift Accessor宏,它接收类型中存储属性的路径(例如\.value),为另一个属性生成基于该存储属性的访问器。已完成宏的定义与部分实现,但在expansion方法中无法确定如何访问类型的成员值。相关代码、示例用法及预期展开效果如下:
宏定义
@attached(accessor) public macro GetSetMacro<Value>(_ : Value) = #externalMacro(module: "MyMacroModule", type: "GetSetMacro")
待完善的宏实现
public struct GetSetMacro: AccessorMacro { public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingAccessorsOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.AccessorDeclSyntax] { guard case let .argumentList(arguments) = node.arguments, let argument = arguments.first else { return [] } return [ """ get { // 如何在此处访问类型的成员值? ??? } """, """ set { ??? = newValue } """ ] } }
示例用法
var value = 1 @GetSetMacro(\.value) var newIntValue: Int
预期展开结果
var newIntValue { get { value } set { value = newValue } }
解决方案
核心是从传入的属性路径参数中提取成员名称,再将其插入到访问器代码模板中。
修改后的完整宏实现
import SwiftSyntax import SwiftSyntaxMacros public struct GetSetMacro: AccessorMacro { public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingAccessorsOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.AccessorDeclSyntax] { guard case let .argumentList(arguments) = node.arguments, let argument = arguments.first?.expression, // 解析属性路径表达式,提取成员标识符 let keyPathExpr = argument.as(KeyPathExprSyntax.self), let component = keyPathExpr.components.first?.as(KeyPathComponentExprSyntax.self), let identifier = component.expression.as(IdentifierExprSyntax.self) else { throw MacroExpansionError(message: "请传入有效的属性路径,格式如\\.value") } let memberName = identifier.identifier.text // 生成get访问器 let getAccessor = try AccessorDeclSyntax(""" get { \(raw: memberName) } """) // 生成set访问器 let setAccessor = try AccessorDeclSyntax(""" set { \(raw: memberName) = newValue } """) return [getAccessor, setAccessor] } }
关键细节
- 属性路径解析:通过
KeyPathExprSyntax拆解传入的\.value表达式,提取出对应的成员名称value。 - 动态生成代码:将提取到的成员名称直接嵌入到get和set的代码模板中,生成符合预期的访问器语法节点。
- 参数校验:增加了错误判断,若传入的参数不是有效的属性路径,会抛出明确的错误提示。
修改后,示例中的宏注解将正确展开为预期的计算属性访问器,直接访问目标成员变量。
内容的提问来源于stack exchange,提问作者hariszaman
相关产品推荐
相关产品推荐

