I know this has been posted a while ago, but I tried to do what the OP asked for as an exercise.
I don’t know how efficient it is, but, here it is:
julia> struct Foo
a::Int
b::Float64
c::Symbol
end
julia> struct StructView{TA,TS,T,N,S} <: AbstractArray{T,N}
data::TA
function StructView(data::AbstractArray{TS,N}, S::Symbol) where {TS,N}
S in fieldnames(TS) || throw(ArgumentError("Struct $(TS) has no field named $S"))
T = typeof(getfield(data[1],S))
TA = typeof(data)
new{TA,TS,T,N,S}(data)
end
end
julia> @inline Base.size(a::StructView) = size(a.data)
julia> @inline Base.getindex(a::StructView{TA,TS,T,N,S}, i::Int) where {TA,TS,T,N,S} = getfield(a.data[i],S)
julia> @inline Base.getindex(a::StructView{TA,TS,T,N,S}, I::Vararg{Int,N}) where {TA,TS,T,N,S} = getfield(a.data[I...],S)
julia> Base.IndexStyle(::Type{StructView{TA,TS,T,N,S}}) where{TA,TS,T,N,S} = IndexStyle(TA)
julia> @inline Base.parent(a::StructView) = a.data
julia> a = Foo(0,1.,:S)
Foo(0, 1.0, :S)
julia> va = fill(a,10)
10-element Array{Foo,1}:
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
Foo(0, 1.0, :S)
julia> viewa = StructView(va,:a)
10-element StructView{Array{Foo,1},Foo,Int64,1,:a}:
0
0
0
0
0
0
0
0
0
0
julia> IndexStyle(typeof(viewa))
IndexLinear()
julia> viewb = StructView(va,:b)
10-element StructView{Array{Foo,1},Foo,Float64,1,:b}:
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
julia> viewc = StructView(va,:c)
10-element StructView{Array{Foo,1},Foo,Symbol,1,:c}:
:S
:S
:S
:S
:S
:S
:S
:S
:S
:S
julia> va[1] = Foo(22,22.,:"22")
Foo(22, 22.0, Symbol("22"))
julia> viewa
10-element StructView{Array{Foo,1},Foo,Int64,1,:a}:
22
0
0
0
0
0
0
0
0
0
julia> viewb
10-element StructView{Array{Foo,1},Foo,Float64,1,:b}:
22.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
julia> viewc
10-element StructView{Array{Foo,1},Foo,Symbol,1,:c}:
Symbol("22")
:S
:S
:S
:S
:S
:S
:S
:S
:S