Существует ли способ "объявить" переменную с конкретным пользовательским типом в MATLAB? нули () только работают на встроенные числовые типы. Единственное решение, которое я предложил, включает использование repmat () для дублирования фиктивных объектных нулевых времен:
arr = repmat(myClass(), [1 0])
Не объявляя переменные этот путь, любой код, который делает "прибытие (end+1) = myClass ()", должен включать особый случай для пустой матрицы по умолчанию, которая имеет тип дважды.
Я пропустил что-то немного более разумное?
Согласно этой документации , все классы имеют пустой метод
, который создает пустые массивы этого класса. Например:
arr = myClass.empty(0,0); %# Creates a 0-by-0 array of class myClass
Это также верно для встроенных типов :
a = uint8.empty(0,1); %# A 0-by-1 uint8 array
b = single.empty(5,0); %# A 5-by-0 single array
c = cell.empty(0,0); %# A 0-by-0 cell array
Вы упомянули, что будете увеличивать этот массив в цикле в следующем способ:
arr(end+1) = myClass();
Если вы знаете, каков будет окончательный размер массива, обычно более эффективно предварительно выделить весь массив вне цикла, а затем перезаписать или изменить элементы массива в вашем цикле. Я обсуждаю, как это можно сделать для определяемых пользователем классов в , ответ на другой вопрос .
Это то, что я использую. Вы можете использовать немного более сложную форму, которая принимает скалярный аргумент размера.
r = repmat(MyClass, 0);
Обратите внимание, что вы не объявляете переменную, чтобы она имела тип; это все еще просто значение, хранящееся в переменной, которая имеет тип.
Это будет работать как со старым, так и с новым стилем классов MCOS. Если вы используете все классы нового стиля, то gnovice's "empty()" звучит как хорошая идея.
Если вы чувствуете себя продвинутым, есть еще один вариант, который я включаю для полноты картины.
Вы также можете обработать это в subsasgn для ваших объектов, по крайней мере, для класса старой школы Matlab. Если вы выполняете индексированное присваивание в унициализированную переменную с объектом, определенным пользователем, на RHS ("правой стороне"), то вызывается subsagn для этого класса, при этом LHS приходит как [] (пустой double). Если у вас есть специальная форма конструктора, позволяющая создавать пустой объект без вызова repmat на объекте, вы можете поддержать это, чтобы пользователям не приходилось предварительно распределять свои переменные с объектами вашего класса.
В вашем subsasgn:
function obj = subsasgn(obj, S, B)
...
s = S(1);
...
switch s.type
case '()'
% Handle dispatch on LHS autovivification
if isnumeric(obj) && isa(B, mfilename('class'))
% Must use special ctor to preallocate
obj = feval(class(B), mxdims(size(B)));
end
Затем в вашем конструкторе сделайте форму вызова бэкдора для конструирования пустых объектов, благословляя предварительно отформатированные структуры.
function MyClass(varargin) %constructor
SuperClasses = { }; % if you inherit, fill this in
if nargin == 1 && isa(varargin{1}, 'mxdims')
% special backdoor to support preallocation without repmat
s = repmat(DataStructure, msize(varargin{1})); % built-in repmat called on plain struct
out = class(s, mfilename, SuperClasses{:});
return;
end
...
Класс @mxdims - это специальный класс, который вам нужно будет создать, который хранит вектор размеров и служит маркером для вызова этой бэкдор-формы. Метод msize() возвращает вектор размеров, который он представляет.
Если вы определите MyClass так, чтобы он поддерживал это, то вы можете просто сделать "s(1) = MyClass" без предварительного распределения s. Однако вы не можете сделать "s(end+1)"; "end" работает только с предварительно распределенными значениями.
Это сложная область Matlab, в которой нужно работать. Подобная работа с subsasgn и системой типов может привести к множеству тонких ошибок, включая segfaults. Делая это таким образом, вы получите более "полное" поведение для ваших объектов, определяемых пользователем. Но это требует работы и хрупкости, и вам, вероятно, лучше придерживаться "repmat(class, 0)" или "empty()".