指定 Julia 函数只能采用内容属于某些类型的 Dicts/Arrays 的正确方法是什么?

What is the correct way to specify that a Julia function can only take Dicts/Arrays whose contents are of certain types?

假设我有一个需要字典作为输入的函数。其中,此函数只能处理特定 Union 允许类型中的该字典的值。对于此参数,输入可以是 NumberStringBool:

allowed_types = Union{String, Int, AbstractFloat, Bool}

该函数还可以允许值是这些允许类型 (Dict{String,allowed_types}) 的字典或项目是这些类型 (Array{allowed_types,Int}) 的数组,因为它们可以 "disassembled" 到这些允许的类型之一。 (这可以继续向下 - 所以数组等数组)

full_allowed_types = Union{allowed_types, Dict{String,allowed_types}, Array{allowed_types,Int}}

然后我可以将函数定义为

function my_func(input::Dict{String,full_allowed_types})
...
end

那么,我如何构造我的函数参数以便我可以通过,即,my_func(Dict("a"=>"astr","b"=>1))?通常,Dict(...) 调用会导致 Dict{String,Any},这无法使用我的函数调用,因为 Any 不是允许的类型。

我当前实现的错误是:

my_func(Dict("a"=>"astr","b"=>1))
ERROR: MethodError: no method matching my_func(::Dict{String,Any})
Closest candidates are:
  my_func(::Dict{String,Union{Bool, Int64, Dict{String,Union{Bool, Int64, AbstractFloat, String}}, AbstractFloat, Array{Union{Bool, Int64, AbstractFloat, String},Int64}, String}}) at <snip>/my_func.jl:41
Stacktrace:
 [1] top-level scope at none:0

我从用户的角度来描绘这个问题,用户可能只是使用默认构造函数创建一个字典,而不考虑 my_func 想要什么 "allowed" (意思是我不'指望他们打电话给 Dict{String,my_pkg.full_allowed_types}(...)).

是最好的选择,只允许 Any 作为 my_func 的输入,然后在遍历输入时如果任何元素不符合我允许的类型则抛出错误?

首先,在创建字典时,您可以像这样指定参数:

d = Dict{String, full_allowed_types}("a" => "astr", "b" => 2)

其次,您创建 my_func 的方法实际上是正确的,并且适用于 d。但是当你创建一个字典时

d2 = Dict{String, Int64}("a" => 1, "b" => 2)

您可能会感到惊讶,您不能用 d 调用 my_func。原因是,即使 Int64full_allowed_types 的子类型,您也只允许类型为 Dict{String, full_allowed_types} 而不是 Dict{String, Int64} 的 Dicts。如果你想也能够传递子类型,你可以声明 my_func like

function my_func(input::Dict{String, <: full_allowed_types})
    ...
end

注意这里额外的<:,这只是

的语法糖
function my_func(input::Dict{String, T}) where {T <: full_allowed_types}
    ...
end
function f(a::Dict{String, A}) where A <: Union{Int,String}
   println("Got elem type $A")
end

用法:

julia> f(Dict{String,Union{String,Int}}("a"=>"astr","b"=>1))
Got elem type Union{Int64, String}

现在如果你想方便用户,你可以添加一个额外的功能(但是,类型转换是有代价的):

function f(a::Dict{String,A}) where A
    @warn "Provided unsupported type of elements $A will try narrow it to Union{Int,String}"
    f(Dict{String,Union{Int,String}}(d))
end

用法示例:


julia> f(Dict("a"=>"astr","b"=>1))
┌ Warning: Provided unsuported type of elements Any will try narrow it to Union{Int,String}
└ @ Main REPL[31]:2
Got elem type Union{Int64, String}