exponenta event banner

Шаблоны кода для методов subsref и subsasgn

Настройка индексированной ссылки и назначения

Определяемые пользователем классы имеют то же поведение индексирования, что и встроенные классы. Классы могут настраивать операции индексирования, перегружая функции, которые MATLAB ® вызывает для вычисления выражений индексирования. Перегрузка subsref и subsasgn функции, если требуется определить специальные варианты поведения для индексированных ссылок и назначений.

Обзор индексирования объектов см. в разделе Индексирование массива объектов.

Синтаксис для методов subsref и subsasn

MATLAB вызывает subsref и subsasgn методы вашего класса с этими аргументами.

МетодВходПродукция

b = subsref(obj,s)

  • obj - Объект или массив объектов, используемый в выражении индексирования

  • s - Структура индексации

b - Результат индексирования выражения

obj = subsasgn(obj,s,b)

  • obj - Объект или массив объектов, используемый в выражении индексирования

  • s - Структура индексации

  • b - Присваиваемое значение

obj - Объект или массив объектов после назначения

Изменение количества аргументов

Если конструкция класса требует, чтобы операции индексирования возвращали или назначали другое количество значений, чем число, определенное операцией индексирования по умолчанию, перегружайте numArgumentsFromSubscript функция для управления nargout для subsref и nargin для subsasgn. Дополнительные сведения и примеры см. в разделе numArgumentsFromSubscript.

Структура индексирования описывает выражения индексирования

Структура индексирования содержит информацию, описывающую выражение индексирования. Методы классов используют информацию в структуре индексирования для вычисления выражения и реализации пользовательского поведения.

Например, CustomIndex класс определяет свойство, которое можно использовать в выражениях индексирования.

classdef CustomIndex
   properties
      DataArray
   end
end

Создайте объект и назначьте матрицу 5 на 5, созданную magic функции к DataArray собственность.

a = CustomIndex;
a.DataArray = magic(5);

Это подстрочное ссылочное выражение возвращает первую строку матрицы 5 на 5.

a.DataArray(1,:)
ans =

    17    24     1     8    15

Это выражение присваивает новые значения первой строке массива, сохраненного в DataArray собственность.

a.DataArray(1,:) = [1 2 3 4 5];

В этой инструкции назначения используются:

  • A '.' ссылка на тип

  • Имя свойства, следующее за точкой (т. е. DataArray)

  • Диапазон индексов (1,:) в скобках

Структура индексирования содержит эту информацию в type и subs поля.

Значения структуры индексирования

При выполнении индексного выражения MATLAB вызывает класс subsref или subsasgn метод, если класс перегружает эти функции. Одним из аргументов, переданных методу, является структура индексирования. Структура индексирования имеет два поля:

  • type - Один из трех возможных типов индексирования: '.', '()', '{}'

  • subs - A char вектор с именем свойства или массивом ячеек индексов, используемых в выражении, включая : и end.

Если индексирующее выражение является составным, то MATLAB передает массив структур, один struct для каждого уровня индексации. Например, в этом выражении:

a.DataArray(1,:)

массив структуры индексации S имеет следующие значения:

  • S(1).type имеет значение '.', указывая, что первая операция индексирования является точкой.

  • s(1).subs задано имя свойства, 'DataArray'

Второй уровень индексации находится во втором элементе структуры индексации:

  • S(2).types имеет значение '()' указывая, что вторая операция индексации является индексацией в скобках

  • S(2).subs установлен в массив ячеек, содержащий индексы {[1],[:]}

Типичные шаблоны для методов индексирования

Для перегрузки subsref и subasgn функции:

  • Определение полного индексного выражения с помощью types и subs поля структуры индексирования.

  • Реализуйте специализированные варианты поведения для операций индексирования, поддерживаемых классом.

  • Возвращает соответствующие значения или измененные объекты в ответ на вызов MATLAB.

A switch оператор является удобным способом обнаружения первого уровня индексации. Существует три типа индексирования - точка, скобки и фигурные скобки. Каждыйcase блок в switch реализует все выражения индексирования, начинающиеся с этого типа индексирования первого уровня.

Методы должны реализовывать все выражения индексирования, поддерживаемые классом. Если вы не настраиваете определенный тип индексирования, вызовите встроенную функцию для обработки этого выражения.

Используйте длину массива структуры индексации и тип индексации, определяющие условные операторы для составных выражений индексации.

Структура кода для subsref Метод

Следующая структура для subsref показывает, как использовать информацию в структуре индексации в условных операторах. Приложение может включать другие выражения, не показанные здесь.

function varargout = subsref(obj,s)
   switch s(1).type
      case '.'
         if length(s) == 1
            % Implement obj.PropertyName
            ...
         elseif length(s) == 2 && strcmp(s(2).type,'()')
            % Implement obj.PropertyName(indices)
            ...
         else
            [varargout{1:nargout}] = builtin('subsref',obj,s);
         end
      case '()'
         if length(s) == 1
            % Implement obj(indices)
            ...
         elseif length(s) == 2 && strcmp(s(2).type,'.')
            % Implement obj(ind).PropertyName
            ...
         elseif length(s) == 3 && strcmp(s(2).type,'.') && strcmp(s(3).type,'()')
            % Implement obj(indices).PropertyName(indices)
            ...
         else
            % Use built-in for any other expression
            [varargout{1:nargout}] = builtin('subsref',obj,s);
         end
      case '{}'
         if length(s) == 1
            % Implement obj{indices}
            ...
         elseif length(s) == 2 && strcmp(s(2).type,'.')
            % Implement obj{indices}.PropertyName
            ...
         else
            % Use built-in for any other expression
            [varargout{1:nargout}] = builtin('subsref',obj,s);
         end
      otherwise
         error('Not a valid indexing expression')
   end

Используя varargout для возвращаемого значения позволяет методу работать с массивами объектов. Например, предположим, что необходимо поддерживать возврат списка, разделенного запятыми, с выражением, подобным следующему:

[x1,...xn] = objArray.PropertyName(Indices)

Это выражение приводит к двухэлементному массиву структуры индексирования. Тип первого уровня - точка ('.') и второй уровень в скобках ('()'). Построить varargout с каждым значением в массиве.

case '.'
   ...
   if length(s)==2 && strcmp(s(2).type,'()')
      prop = s(1).subs;      % Property name
      n = numel(obj);        % Number of elements in array
      varargout = cell(1,n); % Preallocate cell array
      for k = 1:n
         varargout{k} = obj(k).(prop).(s(2).subs);
      end
   end
   ...
end

Шаблон subsasgn

Следующая структура для subsasgn метод показывает, как использовать структуру индексирования в условных операторах, реализующих операции назначения.

function obj = subsasgn(obj,s,varargin)

   % Allow subscripted assignment to uninitialized variable
   if isequal(obj,[])
      % obj = ClassName.empty;
   end

   switch s(1).type
      case '.'
         if length(s) == 1
            % Implement obj.PropertyName = varargin{:};
            ...
         elseif length(s) == 2 && strcmp(s(2).type,'()')
            % Implement obj.PropertyName(indices) = varargin{:};
            ...
         else
            % Call built-in for any other case
            obj = builtin('subsasgn',obj,s,varargin{:});
         end
      case '()'
         if length(s) == 1
            % Implement obj(indices) = varargin{:};
         elseif length(s) == 2 && strcmp(s(2).type,'.')
            % Implement obj(indices).PropertyName = varargin{:};
            ...
         elseif length(s) == 3 && strcmp(s(2).type,'.') && strcmp(s(3).type,'()')
            % Implement obj(indices).PropertyName(indices) = varargin{:};
            ...
         else
            % Use built-in for any other expression
            obj = builtin('subsasgn',obj,s,varargin{:});
         end       
      case '{}'
         if length(s) == 1
            % Implement obj{indices} = varargin{:}
            ...
         elseif length(s) == 2 && strcmp(s(2).type,'.')
            % Implement obj{indices}.PropertyName = varargin{:}
            ...
            % Use built-in for any other expression
            obj = builtin('subsasgn',obj,s,varargin{:});
         end
      otherwise
         error('Not a valid indexing expression')
   end
end

Используя varargin для правого значения оператора назначения позволяет методу работать с массивами объектов. Например, предположим, что необходимо поддерживать назначение списка, разделенного запятыми, с выражением, подобным следующему:

C = {'one';'two';'three'};
[objArray.PropertyName] = C{:}

Это выражение приводит к структуре индексирования с типом точки ('.') индексирование Массив ячеек C в правой части инструкции назначения создается список, разделенный запятыми. Этот код назначает один элемент списка каждому свойству в массиве объектов.

case '.'
   if length(s)==1
      prop = s(1).subs;      % Property name
      n = numel(obj);        % Number of elements in array
      for k = 1:n
         obj(k).(prop) = varargin{k};
      end
   end
end

Подстрочное назначение с неинициализированной переменной

Назначение элементу неинициализированной переменной приводит к вызову subsasgn метод класса в правой части назначения. Например, этот класс определяет subsasgn метод, который просто вызывает встроенный subsasgn способ индексирования в скобках.

classdef MyClass
   methods
      function obj = subsasgn(obj,s,varargin)
         switch s(1).type
            case '()'
               obj = builtin('subsasgn',obj,s,varargin{:});
         end
      end
   end
end

При попытке назначения объекта MyClass к первому элементу неинициализированной переменной, B(1) в следующей инструкции MATLAB вызывает subsasgn способ MyClass с пустым двойником ([]) в качестве первого аргумента. Назначение может вызвать ошибку, так как subsasgn метод должен быть передан объекту класса.

clear B
B(1) = MyClass;
The following error occurred converting from MyClass to double:
Conversion to double from MyClass is not possible.

Error in MyClass/subsasgn (line 6)
            obj = builtin('subsasgn',obj,s,varargin{:});

subsasgn метод может обнаружить эту ситуацию и предпринять соответствующее действие, например, вернуть полезное сообщение об ошибке, если класс не поддерживает этот тип назначения, или преобразовать входные данные в объект класса и передать их subsasgn.

Например, потому что MyClass может разрешить подстрочное назначение неинициализированной переменной, subsasgn метод может изменить первый аргумент с пустого двойника на пустой MyClass объект.

Используйте isequal для проверки входного сигнала и empty статический метод для создания пустого объекта.

classdef MyClass
    methods
        function obj = subsasgn(obj,s,varargin)
            if isequal(obj,[])
                obj = MyClass.empty;
            end
            obj = builtin('subsasgn',obj,s,varargin{:});
        end
    end
end

Назначение подстрочной переменной неинициализированной переменной теперь позволяет избежать предыдущей ошибки.

clear B
B(1) = MyClass;
B = 

  MyClass with no properties.

Связанные темы