我正在尝试编写一个宏来定义字段的 getter 和 setter。 getter/setter 应该称为 Name。但是,当我定义设置器时,过程名称为“Name=”,并且宏似乎试图查找 Name= 的值。如何将“Name=”放入宏中,以便将整个内容解释为过程名称?
更具体地使用以下代码
import macros
type
Test_Type = object of RootObj
Name_HIDDEN: string
macro Name_Macro*(vType: untyped): untyped =
quote do:
proc Name*(self: var `vType`): string =
return self.Name_HIDDEN
proc `Name=`*(self: var `vType`, vIndex: string) =
self.Name_HIDDEN = vIndex
Name_Macro(Test_Type)
var tTest: Test_Type
tTest.Name = "Hello"
echo tTest.Name
我收到以下错误:
test.nim(14, 15) Error: undeclared identifier: 'Name'
candidates (edit distance, scope distance); see '--spellSuggest':
(1, 4): 'name'
你大部分都说对了,但是如果你想使用引用,你需要为设置器预先定义你的标识符吗?
原因是像这样的设置器是运算符并且需要反引号,但是 quote-do 使用反引号来标识插入节点的位置,因此您需要通过首先定义标识符来规避它:
import macros
type
Test_Type = object of RootObj
Name_HIDDEN: string
macro Name_Macro*(vType: untyped): untyped =
let setterName = nnkAccQuoted.newTree("Name".ident, "=".ident)
quote do:
proc Name*(self: var `vType`): string =
return self.Name_HIDDEN
proc `setterName`*(self: var `vType`, vIndex: string) =
self.Name_HIDDEN = vIndex
Name_Macro(Test_Type)
var tTest: Test_Type
tTest.Name = "Hello"
echo tTest.Name
来自 nim 的不和谐服务器的 Elegantbeef 想要指出还有一种使用 std/genast 的方法,它优于 quote do,并且对于这种情况有更好的语义:
import std/[macros, genasts]
type
Test_Type = object of RootObj
Name_HIDDEN: string
macro Name_Macro*(vType: untyped): untyped =
genast(vType):
proc Name*(self: var vType): string =
return self.Name_HIDDEN
proc `Name=`*(self: var vType, vIndex: string) =
self.Name_HIDDEN = vIndex
Name_Macro(Test_Type)
var tTest: Test_Type
tTest.Name = "Hello"
echo tTest.Name