Nim中compileTime引用对象属性修改后值丢失,如何解决?
解决Nim编译时变量属性修改不持久的问题
编译以下代码时,m实例的name属性在setName宏内已被设置,但程序执行结束时该值丢失。需要持久设置name属性,使其像colors序列那样保留修改后的值。
原代码:
import std/macros type MyType = ref object name: string colors: seq[string] proc newMyType(): MyType = new(result) macro setName(m: static[MyType]): untyped = m.name = "foobar" echo "inside macro: ", $m[] newStmtList() var m {.compileTime.} = newMyType() static: m.colors.add("red") m.colors.add("yellow") setName(m) static: echo "at the end: ", $m[]
输出结果:
$ nim c -f --hints:off /tmp/samp inside macro: (name: "foobar", colors: @["red", "yellow"]) at the end: (name: "", colors: @["red", "yellow"])
问题原因
原宏setName的问题在于:它只是在宏自身执行阶段临时修改了编译时变量m的name属性,但没有生成任何实际的编译时执行代码来固化这个修改。宏执行完毕后,这个临时修改不会被保留到后续的编译时环境中,导致最终name值丢失。而colors的修改是在static:块中完成的,这部分代码会被编译时环境执行,因此修改能持久保留。
解决方案
有两种可行的修改方式:
方式一:将宏改为编译时过程(proc)
把setName从宏改成带compileTime pragma的过程,直接在编译时执行修改逻辑:
import std/macros type MyType = ref object name: string colors: seq[string] proc newMyType(): MyType = new(result) proc setName(m: var MyType) {.compileTime.} = m.name = "foobar" var m {.compileTime.} = newMyType() static: m.colors.add("red") m.colors.add("yellow") setName(m) # 在static块中调用编译时proc static: echo "at the end: ", $m[]
方式二:修改宏使其生成编译时执行代码
让宏生成static:块内的赋值语句,确保修改逻辑被编译时环境执行:
import std/macros type MyType = ref object name: string colors: seq[string] proc newMyType(): MyType = new(result) macro setName(m: static[MyType]): untyped = quote do: static: `m`.name = "foobar" echo "inside macro generated code: ", $`m`[] var m {.compileTime.} = newMyType() static: m.colors.add("red") m.colors.add("yellow") setName(m) static: echo "at the end: ", $m[]
验证结果
修改后编译运行,输出会变为:
inside macro generated code: (name: "foobar", colors: @["red", "yellow"]) at the end: (name: "foobar", colors: @["red", "yellow"])
此时name属性的修改已成功持久保留。
内容的提问来源于stack exchange,提问作者iffy
相关产品推荐
相关产品推荐

