Как правильно указать, что функция Julia может принимать только Dicts / Arrays, содержимое которых имеет определенные типы? - PullRequest
2 голосов
/ 28 апреля 2020

Допустим, у меня есть функция, которая ожидает в качестве входных данных dict. В рамках этого эта функция может обрабатывать только значения этого dict, которые находятся в определенном Union разрешенных типов. Для этого аргумента входные данные могут быть Number, String или Bool:

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

Функция также может разрешать Dicts, значения которых являются этими разрешенными типами (Dict{String,allowed_types}), или массивы, чьи элементы являются этими типами (Array{allowed_types,Int}), так как они могут быть "разобраны" до одного из этих разрешенных типов. (Это может продолжать идти вниз - так что массив массивов и т. Д. c)

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

Затем я могу определить свою функцию как

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

Как же тогда я структурирую аргументы моей функции, чтобы я мог передать, IE, 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

Я представляю эту проблему с точки зрения пользователя, где пользователь, скорее всего, просто создаст dict, используя конструктор по умолчанию, без учета того, что my_func хочет "разрешить" (то есть я не ожидаю, что они вызовут Dict{String,my_pkg.full_allowed_types}(...)).

Лучше всего просто разрешить Any в качестве ввода для my_func и затем выдает ошибку, если какой-либо из элементов не соответствует моим разрешенным типам, когда я перебираю ввод?

Ответы [ 2 ]

3 голосов
/ 28 апреля 2020
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}
2 голосов
/ 28 апреля 2020

Во-первых, при создании словаря вы можете указать следующие параметры:

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

Во-вторых, ваш способ создания my_func на самом деле правильный и будет работать с d. Но когда вы создаете словарь

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

, вы можете быть удивлены, что вы не можете вызвать my_func с d. Причина в том, что вы допустили только Dicts типа Dict{String, full_allowed_types}, а не Dict{String, Int64}, хотя Int64 является подтипом full_allowed_types. Если вы хотите иметь возможность передавать также подтипы, вы можете объявить my_func как

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

Обратите внимание на дополнительные <: здесь, это просто syntacti c sugar для

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