索引对象点符号方法给出标量属性

dyl*_*106 14 arrays oop syntax matlab matlab-class

我在使用点符号应用方法后尝试引用对象属性时遇到问题.它只发生在我尝试索引初始对象时

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
Run Code Online (Sandbox Code Playgroud)

然后分配以下内容

A = myclassexample;
A(1).data= - -1;
A(2).data =  -2;
Run Code Online (Sandbox Code Playgroud)

当调用整个数组并收集属性数据时,它工作正常

[A.procData.data]
Run Code Online (Sandbox Code Playgroud)

如果我尝试索引A然后我只得到一个标量

[A([1 2]).procData.data]
Run Code Online (Sandbox Code Playgroud)

即使没有财产电话似乎没事

B  = A([1 2]).procData;
[B.data]
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Amr*_*mro 14

我肯定会把它称为解析器中的一个错误; 一个错误,因为它没有引发错误,而是允许你写: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". 
Run Code Online (Sandbox Code Playgroud)

相反,正如您所指出的,您应该使用:

>> B = procData(A):    % or: B = A.pocData;
>> [B.data]
Run Code Online (Sandbox Code Playgroud)

FWIW,这也是使用普通结构和常规函数(而不是OOP对象和成员函数)时发生的情况,因为无论如何都无法索引函数调用的结果.例:

% 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
Run Code Online (Sandbox Code Playgroud)

然后所有以下调用都会抛出错误(因为它们应该):

% 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". 

>> f=@procStruct; f(s([1 2])).data
Improper index matrix reference. 
Run Code Online (Sandbox Code Playgroud)

您可能会问自己为什么他们决定不允许这样的语法.事实证明,MATLAB不允许索引到函数调用(不必引入临时变量)是一个很好的理由,无论是点索引还是下标索引.

以下面的函数为例:

function x = f(n)
    if nargin == 0, n=3; end
    x = magic(n);
end
Run Code Online (Sandbox Code Playgroud)

如果我们允许索引到函数调用,那么如何解释以下调用会有一个模糊性f(4):

  • 它应该被解释为:( f()(4)即没有参数的调用函数,然后使用线性索引将结果矩阵索引到第4个元素)
  • 或者应该解释为:( f(4)调用函数,其中一个参数为n = 4,并返回矩阵magic(4))

这种混淆是由MATLAB语法中的几个原因引起的:

  • 它允许简单地通过名称调用没有参数的函数,而不需要括号.如果有功能f.m,您可以将其称为ff().这使得解析M代码更难,因为不清楚令牌是变量还是函数.

  • 括号用于矩阵索引和函数调用.因此,如果令牌x表示变量,我们使用语法x(1,2)作为索引到矩阵中.同时if 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?
Run Code Online (Sandbox Code Playgroud)

我们应该从MAX返回每个输出变量的第4个元素,还是仅从第一个输出参数返回第4个元素以及完整的第二个输出?当函数返回不同大小的输出时怎么办?

所有这些仍然适用于其他类型的索引:f()(3)/ f(3),f().x/ f.x,f(){3}/ f{3}.

因此,MathWorks决定避免上述所有混淆,并且不允许直接索引到结果中.不幸的是,他们限制了流程中的语法.例如Octave没有这样的限制(你可以写magic(4)(1,2)),但是新的OOP系统仍在开发中,所以我不知道Octave是如何处理这种情况的.


对于那些感兴趣的人,这让我想起了关于包和类的另一个类似的错误,并直接索引以获取属性.无论您是从命令提示符,脚本还是M文件函数调用它,结果都是不同的...