julia - 如何从 splatted kwargs 字段中检索关键字参数?
问题描述
如果我有一个函数签名f(args...; kwargs...)
,我怎样才能得到一个特定的关键字kwargs
呢?天真的打字 kwargs.x
不起作用:
julia> f(args...; kwargs...) = kwargs.x
f (generic function with 1 method)
julia> f(x=1)
ERROR: type Pairs has no field x
Stacktrace:
[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,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::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 频道上。要自动邀请非常有用的 julia slack,只需填写https://slackinvite.julialang.org
解决方案
发生这种情况的原因是默认情况下,splatted 关键字参数不存储在命名元组中。我们可以看到它们是如何存储的:
julia> g(;kwargs...) = kwargs
g (generic function with 1 method)
julia> g(a=1)
pairs(::NamedTuple) with 1 entry:
:a => 1
julia> g(a=1) |> typeof
Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}
因此,splatted kwargs 被存储为某种迭代器对象。但是,我们可以像这样轻松地将该kwargs
迭代器转换为 NamedTuple:(;kwargs...)
然后以我们期望的方式访问它,因此您的示例将转换为
julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
当然,更惯用的方法是将函数编写为
julia> f(args...; x, kwargs...) = x
f (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)
啊哈!所以我们实际上可以使用它来将 kwargs 作为命名元组,即f(;kwargs...) = kwargs.data.x
可以工作,但我不推荐这种方法,因为它似乎依赖于未记录的行为,所以它可能只是一个不能保证稳定的实现细节跨朱莉娅版本。
推荐阅读
- mongodb - 执行 $map 后,如何在 $addFields 阶段将 $toObjectId 用于 id 数组?
- jquery - 如何从 jQuery 数据表中过滤逗号分隔值和精确值?
- json - 如何将数据从控制器 (JSON) 加载到 View 中的 ListBox?
- c++ - C++ 只调用了一个构造函数
- android - android studio 4.2 无法安装android sdk
- download - 在任何浏览器上停止使用令牌下载文件
- primevue - PrimeVUE 嵌套表格列标题为空?
- angular - 树结构切换可见性,基于选中状态 - Angular
- android - 在安卓设备上安装应用程序,弹出消息似乎被播放保护阻止
- c# - C#如何为每个连接设置不同的代理服务器?