指定 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
允许类型中的该字典的值。对于此参数,输入可以是 Number
、String
或 Bool
:
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
。原因是,即使 Int64
是 full_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}
假设我有一个需要字典作为输入的函数。其中,此函数只能处理特定 Union
允许类型中的该字典的值。对于此参数,输入可以是 Number
、String
或 Bool
:
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
。原因是,即使 Int64
是 full_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}