如何在 Nim 的宏中定义 setter

问题描述 投票:0回答:1

我正在尝试编写一个宏来定义字段的 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'
macros getter-setter nim-lang
1个回答
0
投票

你大部分都说对了,但是如果你想使用引用,你需要为设置器预先定义你的标识符吗?

原因是像这样的设置器是运算符并且需要反引号,但是 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
© www.soinside.com 2019 - 2024. All rights reserved.