如果我具有f(args...; kwargs...)之类的功能签名,如何从kwargs中获取特定的关键字?单纯输入kwargs.x无效:
julia> f(args...; kwargs...) = kwargs.xf (generic function with 1 method)julia> f(x=1)ERROR: type Pairs has no field xStacktrace: [1] getproperty(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}},::Symbol) at ./Base.jl:20 [2] #f#7(::Base.Iterators.Pairs{Symbol,::typeof(f)) at ./REPL[2]:1 [3] (::var"#kw##f")(::NamedTuple{(:x,Tuple{Int64}},::typeof(f)) at ./none:0 [4] top-level scope at REPL[3]:1
此问题出现在#helpdesk的JuliaLang Slack频道中。要自动邀请非常有用的茱莉亚松弛者,只需填写https://slackinvite.julialang.org
发生这种情况的原因是默认情况下,splatted关键字参数未存储在命名元组中。我们可以看到它们的存储方式:
julia> g(;kwargs...) = kwargsg (generic function with 1 method)julia> g(a=1)pairs(::NamedTuple) with 1 entry: :a => 1julia> g(a=1) |> typeofBase.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}
因此,将散布的kwargs存储为某种迭代器对象。但是,我们可以像这样简单地将kwargs迭代器转换为NamedTuple:(;kwargs...),然后以我们期望的方式访问它,因此您的示例将转换为
julia> f(args...; kwargs...) = (;kwargs...).xf (generic function with 1 method)julia> f(x=1,y=2)1
当然,更惯用的方式是将函数编写为
julia> f(args...; x,kwargs...) = xf (generic function with 1 method)julia> f(x=1,y=2)1
,但这假设您在编写函数时知道要访问的名称(x)。
一个简短的旁注:如果返回到示例g(;kwargs...) = kwargs,我们可以要求返回返回的迭代器对象的字段名,如下所示:
julia> g(x=1,y=2) |> typeof |> fieldnames(:data,:itr)
嗯,这个data字段是什么?
julia> g(x=1,y=2).data(x = 1,y = 2)
啊哈!因此我们实际上可以使用kwarg作为命名元组,即f(;kwargs...) = kwargs.data.x可以工作,但是我不推荐这种方法,因为它似乎依赖于未记录的行为,因此它可能仅仅是实现细节不保证在julia版本之间稳定。