Ваша проблема не в push!
, а во внутреннем конструкторе DataHolder
. В частности:
emp = Float64[]
new(emp, emp)
Этот кодовый шаблон означает, что оба поля нового DataHolder
указывают на один и тот же массив (в памяти). Поэтому, если вы изменяете одно из них (скажем, через push!
), вы также изменяете другое.
Вместо этого вы можете заменить эти две строки на:
new(Float64[], Float64[])
чтобы получить желаемое поведение.
В более общем смысле, хотя это не запрещено, использование вами внутреннего конструктора немного странно. Как правило, внутренние конструкторы должны иметь сигнатуру метода, точно соответствующую полям вашей структуры, а сам внутренний конструктор обычно используется только для предоставления набора универсальных тестов, которые должен пройти любой новый DataHolder
.
Лично я бы переписал ваш код следующим образом:
mutable struct DataHolder
data1::Vector{Float64}
data2::Vector{Float64}
function DataHolder(data1::Vector{Float64}, data2::Vector{Float64})
#Any tests on data1 and data2 go here
new(data1, data2)
end
end
DataHolder() = DataHolder(Float64[], Float64[])
Если вам не нужно выполнять какие-либо универсальные тесты для DataHolder
, то полностью удалите внутренний конструктор.
Последняя пища для размышления: действительно ли DataHolder
должно быть изменчивым? Если вы хотите иметь возможность изменять массивы только в data1
и data2
, то сам по себе DataHolder
не должен быть изменяемым, поскольку эти массивы уже изменяемы. Вам нужно, чтобы DataHolder
был изменчивым, только если вы планируете полностью перераспределить значения в этих полях, например, операция вида dh.data1 = [2.0]
.
ОБНОВЛЕНИЕ ПОСЛЕ КОММЕНТАРИИ:
Лично я не вижу ничего плохого в DataHolder() = DataHolder(Float64[], ..., Float64[])
. Это всего лишь одна строка кода, и вам никогда не придется думать об этом снова. В качестве альтернативы вы можете сделать:
DataHolder() = DataHolder([ Float64[] for n = 1:10 ]...)
, который просто разбивает вектор пустых векторов на аргументы конструктора.