问题描述
我有这个结构:
Base.@kwdef struct example_struc
Latitude::Float64 = 9.9 # Latitude (degree)
Longitude::Float64 = -83.7 # Longitude (degree)
end
@kwdef允许我实例化example_struc()
,而无需提供所有参数,这要归功于默认值例如:
@kwdef allows me to instantiate an example_struc()
without giving all arguments thanks to the defaults, e.g.:
julia> a= example_struc(Longitude= 40.0)
julia> a.Latitude
9.93833
julia> a.Longitude
40.0
我想以编程方式(从文件中读取的元组)将其实例化,方法是将参数的名称及其值传递给example_struc
.
I would like to instantiate it programmatically (from a tuple read in a file), by passing to example_struc
the name of the argument, and its value.
我可以使用如下元编程对一个参数执行此操作:
I can do it for one argument using metaprograming like this:
# Named tuple usually read from a file:
params= (Latitude = 43.61, Longitude = 3.877)
params_names= collect(keys(params))
lat= :($(params[1]))
lat_name= :($(params_names[1]))
e= :(example_struc($(lat_name)= $(lat)))
a= eval(e)
e
看起来像这样的:(example_struc(Latitude=43.61))
,而a
与以前完全一样.
e
looks like this :(example_struc(Latitude=43.61))
, and a
is exactly as before.
现在,在我的情况下,参数数量超过了两个(最多50个),因此我需要能够一次对多个参数执行此操作.因此,我尝试使用map作为一个整体传递函数参数:
Now in my case the number of arguments is more than two (up to 50), so I need to be able to do that for multiple arguments at once.So I tried passing the function arguments as a whole using map:
b= map((x,y) -> :($x = $y),params_names,params)
f= :(example_struc($(b...)))
eval(f)
f
看起来像这样::(example_struc(Latitude = 43.61, Longitude = 3.877))
而且行之有效,但这只是因为我们传递了所有参数:我们没有使用默认值.
f
looks like this: :(example_struc(Latitude = 43.61, Longitude = 3.877))
And it works, but only because we pass all the arguments: we are not using the defaults.
现在,如果我想为Longitude
使用默认值,它将无法正常工作:
Now if I want to use a default value for Longitude
, it doesn't work:
b= map((x,y) -> :($x = $y),[params_names[1]],[params[1]])
f= :(example_struc($(b...)))
eval(f)
f
看起来像这样::(example_struc(Latitude = 43.61))
但是现在出现错误:ERROR: MethodError: no method matching example_struc(::Float64)
f
looks like this: :(example_struc(Latitude = 43.61))
But now there is an error : ERROR: MethodError: no method matching example_struc(::Float64)
因此,与其像我期望的那样调用该函数:example_struc(Latitude = 43.61)
,它不如参数名那样调用它:example_struc(43.61)
.
So instead of calling the function like I would expect like this: example_struc(Latitude = 43.61)
, it calls it like this: example_struc(43.61)
, without the parameter name.
关于如何解决此问题的任何想法?我愿意接受任何解决方案,包括更改用户提供输入的方式(但这必须很简单).
Any idea on how to fix this ? I am open to any solution, including changing the way the user gives the inputs (but it has to be simple).
我正在用Julia编写一个程序,该程序读取其中可能包含Julia代码的用户输入文件(这很安全,因为用户仅在本地使用它).因此,输入文件本身就是.jl文件,可以使用evalfile
对其进行评估,并且用户可以在元组中提供参数值,例如:
I'm writing a program in Julia that read a user input file that possibly have Julia code in it (it is safe because the user only use it locally). So the input file is a .jl file itself that is evaluated using evalfile
, and the user provide the parameter values in a Tuple, e.g.:
(
Latitude::Float64 = 9.9, # Latitude (degree)
Longitude::Float64 = -83.7 # Longitude (degree)
some_function= x -> x + 2 # Some functions can be defined by the user (if not, we use the default definition)
)
我的程序读取元组,并且我想提供一些默认值,例如 eg ,如果用户仅放置Latitude
,则程序将使用默认的Longitude
和默认的some_function
.为此,我使用@kwdef结构来利用其默认功能,但我需要知道如何以编程方式传递参数.
My program reads the Tuple, and I would like to provide some default values, e.g. if the user only put the Latitude
, the program uses a default Longitude
and default some_function
. To do so, I use a @kwdef struct to leverage its default capabilities, but I need to know how to pass the arguments programmatically.
推荐答案
您应该能够将一个命名的元组解压缩到构造函数的关键字参数位置.这是一个最小的示例:
You should be able to just unpack a named tuple into the keyword argument position of the constructor. Here's a minimal example:
julia> Base.@kwdef struct A
x::Int64 = 1
y::Int64 = 2
z::Int64 = 3
end
A
julia> kwargs = (z = 5, y = 4)
(z = 5, y = 4)
julia> A(; kwargs...)
A(1, 4, 5)
请注意,您需要在函数调用中使用分号来指示解压缩的参数是关键字参数.如果没有分号,则会出现方法错误:
Note that you need to use the semicolon in the function call to indicate that the unpacked arguments are keyword arguments. Without the semicolon, you'll get a method error:
julia> A(kwargs...)
ERROR: MethodError: no method matching A(::Int64, ::Int64)
Closest candidates are:
A(::Int64, ::Int64, ::Int64) at REPL[13]:2
A(::Any, ::Any, ::Any) at REPL[13]:2
Stacktrace:
[1] top-level scope at none:0
请参阅此处以获取更多详细信息关键字参数.
See here for more details on keyword arguments.
这篇关于以编程方式将参数传递给@kwdef结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!