以编程方式将参数传递给@kwdef结构

时间:2019-07-19 08:29:45

标签: julia

以编程方式将参数传递给@kwdef结构

问题

我有这个结构:

Base.@kwdef struct example_struc
    Latitude::Float64  = 9.9        # Latitude (degree)
    Longitude::Float64 = -83.7      # Longitude (degree)
end

@kwdef允许我实例化example_struc(),而无需使用默认值例如

给出所有参数。
julia> a= example_struc(Longitude= 40.0)
julia> a.Latitude
9.93833
julia> a.Longitude
40.0

我想通过编程方式实例化(从文件中读取的元组),方法是将参数的名称及其值传递给example_struc

我尝试过的

什么有效

我可以使用如下元编程对一个参数执行此操作:

# 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和以前一样。

什么不起作用

现在,在我的情况下,参数数量超过两个(最多50个),因此我需要能够一次对多个参数执行此操作。 因此,我尝试使用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)) 而且行之有效,但这仅仅是因为我们传递了所有参数:我们没有使用默认值。

现在,如果我想为Longitude使用默认值,它将不起作用:

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)

因此,与其像我期望的那样调用该函数:example_struc(Latitude = 43.61),不如不带参数名称地调用它:example_struc(43.61)

关于如何解决此问题的任何想法?我愿意接受任何解决方案,包括更改用户提供输入的方式(但这必须很简单)。

更多背景

我正在用Julia编写一个程序,该程序读取其中可能包含Julia代码的用户输入文件(这很安全,因为用户仅在本地使用它)。因此,输入文件本身就是.jl文件,该文件使用evalfile进行了评估,用户可以在元组中提供参数值,例如:

(
 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结构来利用其默认功能,但我需要知道如何以编程方式传递参数。

1 个答案:

答案 0 :(得分:2)

您应该能够将一个命名的元组解压缩到构造函数的关键字参数位置。这是一个最小的示例:

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)

请注意,您需要在函数调用中使用分号来指示解压缩的参数是关键字参数。如果没有分号,则会出现方法错误:

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了解有关关键字参数的更多详细信息。