Метод нотации объектов с индексированным объектом дает скалярное свойство - программирование
Подтвердить что ты не робот

Метод нотации объектов с индексированным объектом дает скалярное свойство

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

classdef myclassexample

properties
    data
end    

methods   
    function obj = procData(obj)            
        if numel(obj)>1
            for i = 1:numel(obj)
                obj(i) = obj(i).procData;
            end
            return
        end
        %do some processing
        obj.data = abs(obj.data);
    end
end
end

затем присваивая следующее

A = myclassexample;
A(1).data= - -1;
A(2).data =  -2;

при вызове всего массива и сборе данных свойств он отлично работает

[A.procData.data]

если я пытаюсь и индексирую A, тогда я получаю только скаляр

[A([1 2]).procData.data]

несмотря на то, что кажется, что это нормально, без вызова свойства

B  = A([1 2]).procData;
[B.data]

любые идеи?

4b9b3361

Ответ 1

Я бы определенно назвал это ошибкой в ​​синтаксическом анализаторе; Ошибка, потому что она не начала ошибки, и вместо этого вы позволили вам написать: obj.method.prop в первую очередь!

Тот факт, что MATLAB разбился в некоторых вариантах этого синтаксиса, является серьезной ошибкой и определенно должен быть сообщен в MathWorks.

Теперь общее правило в MATLAB заключается в том, что вы не должны "индексировать результат" напрямую. Вместо этого вы должны сначала сохранить результат в переменной, а затем проиндексировать эту переменную.

Этот факт ясен, если вы используете форму func(obj), а не obj.func(), чтобы вызывать методы-члены для объектов (точечная нотация или обозначение функции):

>> A = MyClass;
>> A.procData.data       % or A.procData().data
ans =
     []
>> procData(A).data
Undefined variable "procData" or class "procData". 

Вместо этого, как вы отметили, вы должны использовать:

>> B = procData(A):    % or: B = A.pocData;
>> [B.data]

FWIW, это также происходит при работе с простыми структурами и регулярными функциями (в отличие от объектов ООП и функций-членов), так как вы все равно не можете индексировать результат вызова функции. Пример:

% a function that works on structure scalar/arrays
function s = procStruct(s)
    if numel(s) > 1
        for i=1:numel(s)
            s(i) = procStruct(s(i));
        end
    else
        s.data = abs(s.data);
    end
end

Затем все следующие вызовы будут вызывать ошибки (как они должны):

% 1x2 struct array
>> s = struct('data',{1 -2});

>> procStruct(s).data
Undefined variable "procStruct" or class "procStruct". 

>> procStruct(s([1 2])).data
Undefined variable "procStruct" or class "procStruct". 

>> feval('procStruct',s).data
Undefined variable "feval" or class "feval". 

>> [email protected]; f(s([1 2])).data
Improper index matrix reference. 

Возможно, вы спрашиваете себя, почему они решили не допускать такой синтаксис. Хорошо, что есть хорошая причина, почему MATLAB не позволяет индексировать вызов функции (без необходимости вводить временную переменную), будь то индексирование по индексу или индексирование индекса.

Возьмем следующую функцию, например:

function x = f(n)
    if nargin == 0, n=3; end
    x = magic(n);
end

Если бы мы разрешили индексировать вызов функции, тогда была бы двусмысленность в том, как интерпретировать следующий вызов f(4):

  • следует интерпретировать его как: f()(4) (то есть функцию вызова без аргументов, затем проиндексировать в результирующую матрицу с помощью линейной индексации, чтобы получить 4-й элемент)
  • или он должен интерпретироваться как: f(4) (вызовите функцию с одним аргументом n = 4 и верните матрицу magic(4))

Эта путаница вызвана несколькими вещами в синтаксисе MATLAB:

  • он позволяет вызывать функцию без аргументов просто по имени, не требуя скобок. Если есть функция f.m, ее можно назвать либо f, либо f(). Это усложняет синтаксический анализ M-кода, потому что неясно, являются ли токены переменными или функциями.

    Скобки
  • используются как для индексирования матриц, так и для вызовов функций. Поэтому, если токен x представляет переменную, мы используем синтаксис x(1,2) как индексирование в матрицу. В то же время, если x - это имя функции, то x(1,2) используется для вызова функции с двумя аргументами.

Еще одна путаница - это списки и функции, разделенные запятыми, которые возвращают несколько выходов. Пример:

>> [mx,idx] = max(magic(3))
mx =
     8     9     7
idx =
     1     3     2

>> [mx,idx] = max(magic(3))(4)     % now what?

Должен ли мы вернуть 4-й элемент каждой выходной переменной из MAX или 4-й элемент только из первого выходного аргумента вместе с полным вторым выходом? Как насчет того, когда функция возвращает выходы разных размеров?

Все это относится к другим типам индексирования: f()(3)/f(3), f().x/f.x, f(){3}/f{3}.

Из-за этого MathWorks решила избежать всего вышеперечисленного путаницы и просто не разрешить прямое индексирование результатов. К сожалению, они ограничили синтаксис в этом процессе. Например, Octave не имеет такого ограничения (вы можете написать magic(4)(1,2)), но опять же новая система OOP все еще находится в процессе разработки, поэтому я не знаю, как Octave имеет дело с такими случаями.


Для интересующихся это напоминает мне еще одну похожую ошибку в отношении пакетов и классов и прямое индексирование для получения свойства. Результаты были разными, если вы вызвали его из командной строки, из script или из функции M файла...