Джулия: Как я могу определить тип аргумента функции как массив кортежей? - PullRequest
1 голос
/ 13 мая 2019

У меня есть одномерный массив кортежей, который мне нужно передать в функцию, определенную как

function f(a::Array{Tuple{Vararg{String}}, 1}) 
    #do some processing
end

Каждый кортеж может иметь любое количество элементов String, но количество элементов будет одинаковымдля всех кортежей в массиве.Например, массив может выглядеть как [("x1","x2"),("y1","y2")] или [("x1","x2","x3"),("y1","y2","y3")] и т. Д. Следовательно, для этого используется Vararg {String}.

Теперь, когда я запускаю f([("x1","x2"),("y1","y2")]), он выдает ошибку

"Ошибка метода: метод не соответствует f (:: Array {Tuple {String, String}, 1})"

Как изменить определение функции, чтобы это работало?

Ответы [ 2 ]

4 голосов
/ 13 мая 2019

Вы получаете это MethodError, потому что Tuple{Vararg{T}} не является конкретным типом, так как число элементов для Vararg не определено, а Параметры типа Юлии инвариантны , а не ковариант .

Несмотря на то, что у нас есть Tuple{Vararg{String, 5}} <: Tuple{Vararg{String}}, у нас нет Vector{Tuple{Vararg{String, 5}}} <: Vector{Tuple{Vararg{String}}}

julia> Tuple{Vararg{String, 5}} <: Tuple{Vararg{String}}
true

julia> Vector{Tuple{Vararg{String, 5}}} <: Vector{Tuple{Vararg{String}}}
false

Вместо этого вы должны использовать следующие подписи, чтобы избавиться отошибка

function f(a::Vector{<:Tuple{Vararg{String}}})
# or
function f(a::Vector{T}) where {T <: Tuple{Vararg{String}}

в соответствии с предложениями @crstnbr и @ BogumiłKamiński.Эти сигнатуры избавят от ошибки, однако они не ограничивают кортежи одинаковой длины.Например, вы можете вызывать эти функции с помощью

f([("x1, x2"), ("y1", "y2", "y3"])

Поскольку вы хотите, чтобы кортежи в массиве содержали одинаковое количество элементов, вам нужно указать это ограничение в аннотации типа.Документация для Vararg содержит информацию о том, как указать количество элементов.

Vararg{T,N}

Последний параметр типа кортежа Tuple может быть специальным типом Vararg., который обозначает любое количество конечных элементов.Тип Vararg{T,N} соответствует в точности N элементам типа T.Vararg{T} соответствует нулю или более элементам типа T.Vararg типы кортежей используются для представления аргументов, принимаемых методами varargs (см. Раздел «Функции Varargs» в руководстве.)

Вы можете использовать

function f(a::Vector{Tuple{Vararg{String, N}}}) where N 
    ...
end

илииспользуя компактный способ NTuple вместо

function f(a::Vector{NTuple{N, String}}) where N

end

Эти подписи будут обеспечивать ограничения, которые вы хотели в вопросе.


Примечания

Возможно, вы чрезмерно специализируете свои типы .

Как заметил @ Bogumił Kamiński в разделе комментариев, лучше работать с типом AbstractString вместо конкретного типа String.

function f(a::Vector{<:NTuple{N, AbstractString}}) where N
...
end

Вы также можете рассмотреть возможность работы с AbstractVector вместо Vector.

1 голос
/ 13 мая 2019

Вы можете изменить подпись на

function f(a::Array{<:Tuple{Vararg{String}}, 1})
    #do some processing
end

Обратите внимание на <:, чтобы указать, что все подтипы Tuple{Vararg{String}} в порядке.

Однако, может быть проще просто оставитьиз информации о типе.Функция будет иметь точно такую ​​же скорость.

...