我有这个结构:
Base.@kwdef struct example_struc
Latitude::Float64 = 9.9 # Latitude (degree)
Longitude::Float64 = -83.7 # Longitude (degree)
end
Run Code Online (Sandbox Code Playgroud)
example_struc()由于默认值,@kwdef 允许我在不提供所有参数的情况下实例化 an ,例如:
julia> a= example_struc(Longitude= 40.0)
julia> a.Latitude
9.93833
julia> a.Longitude
40.0
Run Code Online (Sandbox Code Playgroud)
我想通过传递给example_struc参数的名称及其值以编程方式(从文件中读取的元组)实例化它。
我可以使用这样的元编程为一个论点做到这一点:
# Named tuple usually read from a file:
params= (Latitude = 43.61, Longitude = 3.877)
params_names= collect(keys(params))
Run Code Online (Sandbox Code Playgroud)
lat= :($(params[1]))
lat_name= :($(params_names[1]))
e= :(example_struc($(lat_name)= $(lat)))
a= eval(e)
Run Code Online (Sandbox Code Playgroud)
e看起来像这样:(example_struc(Latitude=43.61)),并且和a以前完全一样。
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)
Run Code Online (Sandbox Code Playgroud)
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.
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)
Run Code Online (Sandbox Code Playgroud)
f looks like this: :(example_struc(Latitude = 43.61))
But now there is an error : ERROR: MethodError: no method matching example_struc(::Float64)
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).
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)
)
Run Code Online (Sandbox Code Playgroud)
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.
您应该能够将命名元组解压到构造函数的关键字参数位置。这是一个最小的例子:
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)
Run Code Online (Sandbox Code Playgroud)
请注意,您需要在函数调用中使用分号来指示解压的参数是关键字参数。如果没有分号,您将收到方法错误:
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
Run Code Online (Sandbox Code Playgroud)
有关关键字参数的更多详细信息,请参阅此处。