如何在 Nim 中编写宏 list.findBy(key, value)?
How to write macro list.findBy(key, value) in Nim?
是否可以编写 list.findBy(key, value)
宏,以便:
let people = @[(name: "John"), (name: "Sarah")]
echo people.findBy("name", "John")
理想情况下,它应该在编译时验证“名称”。
我尝试了一些代码,但它不起作用,play:
import macros, options
macro findBy*[T](list: seq[T], field: string, value: untyped): Option[T] =
quote do:
for v in list:
if v.`field` == value: return
let people = @[(name: "John"), (name: "Sarah")]
echo people.findBy("name", "John")
Here 是一个正常运行的实现。
import macros, options, typetraits
macro findBy*[T](list: seq[T], field: untyped, value: untyped): untyped =
quote do:
var res = none(`list`.elementType)
for v in `list`:
if v.`field` == `value`:
res = some(v)
break
res
let people = @[(name: "John"), (name: "Sarah")]
echo people.findBy(name, "John")
您可以使用@Jason 的实现,尽管在这种特殊情况下 tempate
就足够了(没有必要使用 quote do
)
import std/[macros, options]
template findBy*[T](list: seq[T], field: untyped, value: untyped): Option[T] =
var res: Option[T] # Create result variable
for v in `list`: # Splice all parameters into loop
if v.`field` == `value`:
res = some(v)
res # 'return' from template is a final expression
let people = @[(name: "John"), (name: "Sarah")]
expandMacros:
echo people.findBy(name, "John")
# ^ Note that `name` is passed as identifier, not string
这将打印
Some((name: "John"))
findBy
的扩展代码如下所示:
echo [
var res`gensym0: Option[T]
for v`gensym0 in items(people):
if v`gensym0.name == "John":
res`gensym0 = some(v`gensym0)
res`gensym0]
是否可以编写 list.findBy(key, value)
宏,以便:
let people = @[(name: "John"), (name: "Sarah")]
echo people.findBy("name", "John")
理想情况下,它应该在编译时验证“名称”。
我尝试了一些代码,但它不起作用,play:
import macros, options
macro findBy*[T](list: seq[T], field: string, value: untyped): Option[T] =
quote do:
for v in list:
if v.`field` == value: return
let people = @[(name: "John"), (name: "Sarah")]
echo people.findBy("name", "John")
Here 是一个正常运行的实现。
import macros, options, typetraits
macro findBy*[T](list: seq[T], field: untyped, value: untyped): untyped =
quote do:
var res = none(`list`.elementType)
for v in `list`:
if v.`field` == `value`:
res = some(v)
break
res
let people = @[(name: "John"), (name: "Sarah")]
echo people.findBy(name, "John")
您可以使用@Jason 的实现,尽管在这种特殊情况下 tempate
就足够了(没有必要使用 quote do
)
import std/[macros, options]
template findBy*[T](list: seq[T], field: untyped, value: untyped): Option[T] =
var res: Option[T] # Create result variable
for v in `list`: # Splice all parameters into loop
if v.`field` == `value`:
res = some(v)
res # 'return' from template is a final expression
let people = @[(name: "John"), (name: "Sarah")]
expandMacros:
echo people.findBy(name, "John")
# ^ Note that `name` is passed as identifier, not string
这将打印
Some((name: "John"))
findBy
的扩展代码如下所示:
echo [
var res`gensym0: Option[T]
for v`gensym0 in items(people):
if v`gensym0.name == "John":
res`gensym0 = some(v`gensym0)
res`gensym0]