Можно ли определить структуру julia с постоянными требованиями к размерам полей?

#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».