Как я могу указать тип для аргумента функции, не ограничивая его размеры?
В Julia я хочу указать тип аргумента функции в виде массива массивов. Так что я
function foo{T <: Any}(x::Array{Array{T}})
но если я поставлю аргумент x
в REPL, например:
x = Array[[0,1],[1,2,3],[0,1,2,4]]
затем он автоматически получает следующее назначение типа (например), которое включает его размеры:
x::Array{Array{T,N},1}
так что я получаю ошибку
ERROR: `foo` has no method matching foo(::Array{Array{T,N},1}).
Я не хочу вообще ограничивать размеры массива, поэтому думал, что решение может быть чем-то вроде
function foo{T <: Any, N <: Number}(x::Array{Array{T,N},N})
но это тоже не работает.
Как я могу указать тип аргумента, чтобы быть массивом массивов?
1 ответ
Дан массив массивов x = Array[isodd(i) ? [1i,2i] : [1.0i 2.0i] for i=1:10]
Юлия сообщает свой тип как Array{Array{T,N},1}
, Это обманчиво, так как кажется, что существует T
и немного N
для которого вышеуказанный тип будет соответствовать. Но это не так: нечетные элементы будут иметь тип Array{Int,1}
и вечера Array{Float64,2}
, Поэтому, когда вы пытаетесь написать метод для foo
с параметрами типа:
foo{T,N}(::Array{Array{T,N},1}) = T,N
Что T
а также N
за x
? Понятно, что такого N нет - это и 1, и 2! И элементы этих подмассивов не имеют типа Any
- они оба Int
а также Float64
, То же самое относится и к Array[[0,1],[0,1,2]]
хотя в вашем примере вы знаете, что T
а также N
непротиворечивы, система типов Джулии не... и вы могли бы потенциально выдвигать элементы, которые не являются векторами Int.
Есть немало способов обойти это. Наилучший подход состоит в том, чтобы убедиться, что ваши массивы всегда имеют конкретные (или хотя бы одинаковые) типы элементов, но это не всегда возможно. Учитывая ваш пример x
выше, вы могли бы вместо этого написать: x = Array{Int,1}[[0,1],[1,2,3],[0,1,2,4]]
,
Другой вариант - изменить сигнатуру вашей функции:
foo{N}(x::Array{Array,N}) = 1 # Will *only* work for arrays like x above
foo{T<:Array, N}(x::Array{T,N} = 2 # Will work for all arrays of arrays
Первый будет применяться только в том случае, если у вас точно такой тип из-за неизменности, тогда как второй будет работать для всех массивов массивов, как плохо набранных, так и конкретных.
(Изменить: В качестве заключительной записки, N<:Number
не будет соответствовать буквальным числам. Это будет соответствовать типам, которые являются подтипом Number
, лайк Real
или же Int
, В настоящее время нет способа выразить, что параметр типа должен быть значением типа Int
вне соглашения, что N является целым числом).