#julia
Вопрос:
Если я определю новую структуру как
mutable struct myStruct data::AbstractMatrix labels::Vector{String} end
и я хочу выдать ошибку , если длина labels
не равна количеству столбцов data
, я знаю, что могу написать конструктор, который выполняет это условие, например
myStruct(data, labels) = length(labels) != size(data)[2] ? error("Labels incorrect length") : new(data,labels)
Однако после инициализации структуры labels
полю может быть присвоена неправильная длина:
m = myStruct(randn(2,2), ["a", "b"]) m.labels = ["a"]
Есть ли способ выдать ошибку, если labels
поле когда-либо имеет длину, не равную количеству столбцов в data
нем ?
Комментарии:
1. Если количество столбцов не слишком велико, вы можете использовать кортежи и, возможно, StaticArrays.jl.
2. Согласен с DNF, в общем-то Юля не имеет «частный» или «заблокирована», так что делать это немного зависит от usecase. Например. Таблицы данных скрывает имена столбцов в
DataFrames.Index
структуру и делая все неизменным, хотя в конечном итоге пользователь все еще мог связываться с этим, напримерpush!
ную метку на массив, который содержит имена. Они также предлагаютrename!
функцию, направляющую пользователей к безопасному способу переименования (что затем приводит к ошибкам, если пользователи указывают неправильное количество меток).3. @DNF о чем
SizedArray
? Он только обертывает другой массив с размером, он не должен быть типом битов, какStaticArrays
и не ограничен массивами, которые должны быть маленькими, как я понял, т. Е.:mem = OffsetVector(SizedVector{0x10000 |gt; Int}(zeros(UInt8, 0x10000)), 0x0:0xffff)
Например, это плохое использование?4. Я не использовал
SizedArray
, но это также часть StaticArrays.jl
Ответ №1:
Вы могли бы использовать StaticArrays.jl
для исправления размеров матрицы и вектора для начала:
using StaticArrays mutable struct MatVec{R, C, RC, VT, MT} data::MMatrix{R, C, MT, RC} # RC should be R*C labels::MVector{C, VT} end
но есть и обратная сторона необходимости компиляции для каждого конкретного типа с уникальной перестановкой параметров типа R,C,MT,VT
. StaticArrays
также не масштабируется так хорошо, как обычные Array
s.
Если вы не ограничиваете размеры в параметрах типа (со всеми этими недостатками) и хотите выдать ошибку во время выполнения, у вас есть хорошие и плохие новости.
Хорошая новость в том, что вы можете контролировать любые мутации, происходящие с вашим типом. m.labels = v
вызовет метод setproperty!(object::myStruct, name::Symbol, v)
, который вы можете определить со всеми необходимыми гарантиями.
Плохая новость заключается в том, что вы не можете контролировать мутацию типов полей. push!(m.labels, 1)
мутирует в push!(a::Vector{T}, item)
методе. Сам myStruct
экземпляр на самом деле не меняется; он по-прежнему указывает на то же Vector
самое . Если вы не можете гарантировать , что не сделаете что-то подобное x = m.labels; push!(x, "whoops")
, тогда вам действительно нужны проверки во время выполнения, например iscorrect(m::myStruct) = length(m.labels) == size(m.data)[2]
Комментарии:
1. О чем
StaticArrays.SizedArray
? Пожалуйста, смотрите мой комментарий выше.2. @HarmonicaMuse Да, это тоже вариант. Я не знаю, как для этого масштабируется производительность, в документах упоминается, что
SizedArray
s используют некоторые методы статического массива. Однако стоит отметить, что для этого все равно потребуется компиляция для каждогоR,C,MT,VT
.3. Мне пришло в голову, что вы можете, по крайней мере, избежать этой
push!
проблемы, не вводя размеры в параметры типа MyStruct: убедитесьlabels
, что этоSubArray
(view
конструктор). Вы все ещеpush!
my_struct.labels.parent
можете это сделать , но, по крайней мере, это не будет видноmy_struct.labels
. Однакоinsert!
в родительском массиве также будут смещаться элементы в представлении. Действительно, любой подход, основанный на массиве 1D, далеко не так устойчив, какStaticArrays
использование вместо этого матрицы 2D (1xC).
Ответ №2:
Хороший вариант-не обращаться напрямую к полям вашей структуры. Вместо этого сделайте это с помощью функции. Напр.:
mutable struct MyStruct data::AbstractMatrix labels::Vector{String} end function modify_labels(s::MyStruct, new_labels::Vector{String}) # do all checks and modifications end
Вам следует ознакомиться с главой 8 из раздела «Практические шаблоны проектирования и лучшие практики работы с Джулией: проверенные решения распространенных проблем при разработке программного обеспечения для Julia 1.x».