Юлия переопределяет индексы при доступе к массиву - PullRequest
0 голосов
/ 27 марта 2019

У меня есть структура, реализующая интерфейс Array. Я хочу переопределить индексы при доступе к нему. До сих пор я делал это в функции Base.getindex для моего типа, но я видел функцию Base.to_indices в документе и не знаю, как они работают вместе.

Можно получить доступ к элементам массива, используя : (Colon), UnitRange, StepRange, OneTo, Int или Int arrays, поэтому где я должен переопределять индексы без необходимости справиться со всеми этими делами?

1 Ответ

2 голосов
/ 27 марта 2019

Трудно об этом говорить абстрактно. Вот конкретный пример:

struct ReversedRowMajor{T,A} <: AbstractMatrix{T}
    data::A
end
ReversedRowMajor(data::AbstractMatrix{T}) where {T} = ReversedRowMajor{T, typeof(data)}(data)
Base.size(R::ReversedRowMajor) = reverse(size(R.data))
Base.getindex(R::ReversedRowMajor, i::Int, j::Int) = R.data[end-j+1, end-i+1]

Этот простой массив обращается к родительскому массиву с его переставленными индексами (чтобы быть основным рядом) и преобразованным (чтобы быть обращенным). Обратите внимание, что этот массив автоматически поддерживает все ожидаемые формы индексации:

julia> R = ReversedRowMajor([1 2; 3 4; 5 6])
2×3 ReversedRowMajor{Int64,Array{Int64,2}}:
 6  4  2
 5  3  1

julia> R[:, isodd.(R[1,:].÷2)]
2×2 Array{Int64,2}:
 6  2
 5  1

julia> @view R[[1,4,5]]
3-element view(reshape(::ReversedRowMajor{Int64,Array{Int64,2}}, 6), [1, 4, 5]) with eltype Int64:
 6
 3
 2

Обратите внимание, что мы не переиндексируем в R переставленные и вычисленные индексы - новые индексы передаются непосредственно в родительский массив R.data.

Теперь, to_indices, с другой стороны, выполняет простые преобразования ранее неподдерживаемого индекса типов в Int или массивов Int, а затем переиндексирует в R сам с эти преобразованные индексы. Обратите внимание, что происходит, когда вы звоните R[Int8(1),Int8(1)]:

julia> @which R[Int8(1),Int8(1)]
getindex(A::AbstractArray, I...) in Base at abstractarray.jl:925

Это не вызывает метод, который вы определили - пока нет. Вы не определили, как getindex(::ReversedRowMajor, ::Int8, ::Int8). Итак, Джулия занимается этим делом для вас. Он использует to_indices для преобразования Int8 в Int, а затем снова вызывает R[1,1] . Теперь он попадает в метод, который вы определили.

Вкратце: Этот массив имеет простой метод getindex с индексами Int, который пересчитывает доступы в родительский массив . to_indices, с другой стороны, преобразует все другие типы индексов в поддерживаемые индексы в тот же массив в тех случаях, когда вы не определили метод сопоставления. Вы просто не можете выполнить нужное преобразование с помощью to_indices, потому что неясно, использует ли R[1, 2] пре-преобразованные индексы или пост-преобразованные индексы.

...