Julia: Массивы с абстрактными параметрами вызывают ошибки, но переменные с абстрактными типами не
руководство стиля Джулии говорит следующее:
Не используйте ненужные статические параметры. Функциональная подпись:
foo{T<:Real}(x::T) = ...
должен быть записан как:
foo(x::Real) = ...
Я ожидал, что также применить параметры массива. Однако, если я напишу следующий код:
ret1(x::Real) = x
ret2(x::Array{Float64,2}) = x
ret3(x::Array{Real,2}) = x
ret1(1.0)
ret2(rand(2,2))
ret3(rand(2,2))
то я получаю следующий вывод консоли (используя Julia 0.2.1):
MethodError(ret3,(
2x2 Array{Float64,2}:
0.841121 0.322133
0.469432 0.495438,))
Итак, почему Джулия выдает ошибку для массивов с абстрактными параметрами типа, но не для переменных с абстрактными типами?
Ответы
Ответ 1
В случае ret3
параметр типа действительно необходим, потому что a Array{Real}
- тип, который никогда не может быть построен. Параметры типа Юлии являются инвариантными. Это немного тонкая тема, но ключевым фактом является то, что, хотя Float64 <: Real
истинно, Array{Float64} <: Array{Real}
нет. Сначала это немного запутывает, но это необходимо для того, чтобы компилятор мог знать макет памяти аргументов функции при создании кода. Подробнее см. manual.
Итак, вы можете отправить Real
как в ret1
, потому что, когда вы передаете его, Float64
, Float64 <: Real
истинно, тогда как в ret3
вы передаете его Array{Float64}
и Array{Float64} <: Array{Real}
это не так, следовательно, ошибка метода. Чтобы исправить это, используйте параметр типа:
julia> ret3{T <: Real}(x::Array{T,2}) = x
ret3 (generic function with 2 methods)
julia> ret3(rand(2,2))
2x2 Array{Float64,2}:
0.0857132 0.353194
0.802737 0.717292
Ответ 2
В случае ret3
ожидается строго Array{Real, 2}
, т.е. массив, который может содержать любые переменные Real
внутри (в то время как rand(2,2)
- это массив только Float64
).
В этом случае статический параметр не нужен:
ret3{T<:Real}(x::Array{T,2}) = x
Ответ 3
Начиная с julia 1.2, я считаю, что для ret3
необходимо набрать:
ret3(x::Array{<:Real,2})