Julia:如何在宏中使用kwargs…?

3

假设我想

@fn a :b :c sort=true

扩展到

gn(a, :b, :c, sort=true)

目前,我正在撰写此内容

macro fn(x, args..., kwargs...)
    esc(:(gn($x, $(args...), $(kwargs...))))
end

这似乎不起作用。

我如何扩展kwargs...,就像宏一样?

2个回答

3

无论如何,你都需要使用冒号来区分args和kwargs,但是:

julia> macro fn(x, args...; kwargs...)
           esc(:(gn($x, $(args...), $(kwargs...))))
       end
ERROR: syntax: macros cannot accept keyword arguments
Stacktrace:
 [1] top-level scope at REPL[2]:1

当然,您可以自己解析“伪关键字参数”。它们只是作为赋值语句传递:

julia> dump(:(@fn a :b :c sort=true))
Expr
  head: Symbol macrocall
  args: Array{Any}((6,))
    1: Symbol @fn
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[5]
    3: Symbol a
    4: QuoteNode
      value: Symbol b
    5: QuoteNode
      value: Symbol c
    6: Expr
      head: Symbol =
      args: Array{Any}((2,))
        1: Symbol sort
        2: Bool true

3

以下是遵循@phipsgabler评论的完整代码:

function gn(x, args...;kwargs...)
    println("I am called with x=$x args=$args kwargs=$kwargs")
end

macro fn(x, args...)
    aargs = []
    aakws = Pair{Symbol,Any}[]
    for el in args
        if Meta.isexpr(el, :(=))
            push!(aakws, Pair(el.args...))
        else
            push!(aargs, el)
        end
    end
    quote
        gn($x, $aargs...; $aakws...)
    end
end

测试:

julia> @fn sin 1 2 3 x=4 y=8
I am called with x=sin args=(1, 2, 3) kwargs=Base.Iterators.Pairs(:x => 4,:y => 8)

1
它还有一个额外的好处,允许使用@fn sin z=1 1 2 3 x=4 y=8。 - xiaodai
2
我建议使用 Meta.isexpr(el, :(=)) 作为条件。 - phipsgabler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接