I have a struct
containing fields, some of which are multidimensional Array
s, however I want to be able to copy (both deep and shallow) between instances of this type. Comments on an answer from SO indicate that this can be done using
Base.copy(x::T) where T = T([getfield(x, k) for k ∈ fieldnames(T)]...)
Base.deepcopy(x::T) where T = T([deepcopy(getfield(x, k)) for k ∈ fieldnames(T)]...)
Whilst this copy
functions accordingly, the deepcopy
does not appear to work for arrays, i.e.
mutable struct MyStruct1
field1::Array{Float64,1}
end
mutable struct MyStruct2
field1::Array{Float64,1}
field2::Array{Float64,2}
end
Base.copy(x::T) where T = T([getfield(x, k) for k ∈ fieldnames(T)]...)
Base.deepcopy(x::T) where T = T([deepcopy(getfield(x, k)) for k ∈ fieldnames(T)]...)
ms1a = MyStruct1(zeros(1))
# MyStruct1([0.0])
ms1b = copy(ms1a)
# MyStruct1([0.0])
ms1c = deepcopy(ms1a)
# MyStruct1(Float64[])
ms2a = MyStruct2(zeros(1), zeros(1,1))
# MyStruct2([0.0], [0.0])
ms2b = copy(ms2a)
# MyStruct2([0.0], [0.0])
ms2c = deepcopy(ma2a)
ERROR: MethodError: no method matching Array{Float64,2}()
Closest candidates are:
Array{Float64,2}(::UndefInitializer, ::Int64, ::Int64) where T at boot.jl:404
Array{Float64,2}(::UndefInitializer, ::Int64...) where {T, N} at boot.jl:408
Array{Float64,2}(::UndefInitializer, ::Tuple{Int64,Int64}) where T at boot.jl:412
...
Stacktrace:
[1] deepcopy(::Array{Float64,2}) at ./REPL[4]:1
[2] (::getfield(Main, Symbol("##5#6")){MyStruct2})(::Symbol) at ./none:0
[3] collect_to!(::Array{Array{Float64,1},1}, ::Base.Generator{Tuple{Symbol,Symbol},getfield(Main, Symbol("##5#6")){MyStruct2}}, ::Int64, ::Int64) at ./generator.jl:47
[4] collect_to_with_first!(::Array{Array{Float64,1},1}, ::Array{Float64,1}, ::Base.Generator{Tuple{Symbol,Symbol},getfield(Main, Symbol("##5#6")){MyStruct2}}, ::Int64) at ./array.jl:630
[5] collect(::Base.Generator{Tuple{Symbol,Symbol},getfield(Main, Symbol("##5#6")){MyStruct2}}) at ./array.jl:611
[6] deepcopy(::MyStruct2) at ./REPL[4]:1
[7] top-level scope at none:0
I assume that the first deepcopy
shown here returning MyStruct1(Float64[])
is indicative of an underlying issue, but what is it doing that the 1D case isn’t throwing an error and how do I rectify this?
Edit: Might it also be possible to have both as “member functions” of the struct, as discussed in discourse here?