问题
I have a structure implementing the Array interface. I want to redefine the indices when accessing it. So far, I did it in the Base.getindex function for my type, but I have seen the Base.to_indices function in the doc and do not know how they work together.
It is possible to access array elements using : (Colon), UnitRange, StepRange, OneTo, Int or Int arrays, so where should I redefine the indices without having to manage all these cases?
回答1:
It's hard to talk about this in the abstract. Here's a concrete example:
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]
This simple array accesses the parent array with its indices permuted (to be row major) and transformed (to be reversed). Note that this array automatically supports all the expected forms of indexing:
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
Note that we're not re-indexing into R with the permuted and computed indices — the new indices are given directly to the parent array R.data.
Now, to_indices, on the other hand, does simple transformations of previously unsupported index types to either Int or arrays of Int and then re-indexes into R itself with those transformed indices. Note what happens when you call R[Int8(1),Int8(1)]:
julia> @which R[Int8(1),Int8(1)]
getindex(A::AbstractArray, I...) in Base at abstractarray.jl:925
This isn't calling any method you defined — not yet. You didn't define how to getindex(::ReversedRowMajor, ::Int8, ::Int8). So Julia is handling that case for you. It uses to_indices to convert the Int8 to an Int and then calls R[1,1] again. Now it hits the method you defined.
In short: This array has a simple getindex method with Int indices that recomputes accesses into a parent array. to_indices, on the other hand, transforms all the other types of indices to supported indices into the same array in cases where you've not defined a matching method. You're simply not able to do the sort of transformation you want with to_indices because it's not clear if R[1, 2] is using the pre-transformed indices or the post-transformed indices.
来源:https://stackoverflow.com/questions/55380076/julia-redefining-indices-when-accessing-an-array