我肯定会将此称为解析器中的错误;一个错误,因为它一开始就没有抛出错误,而是允许你写: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,在使用普通结构和常规函数(与 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
然后所有以下调用都会抛出错误(应该如此):
% 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.
您可能会问自己为什么他们决定不允许这样的语法。事实证明,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
or 或f()
。这使得解析 M 代码更加困难,因为不清楚标记是变量还是函数。
括号用于矩阵索引和函数调用。因此,如果一个标记x
表示一个变量,我们使用语法x(1,2)
作为矩阵的索引。同时 ifx
是函数的名称,thenx(1,2)
用于调用带有两个参数的函数。
另一个混淆点是返回多个输出的逗号分隔列表和函数。例子:
>> [mx,idx] = max(magic(3))
mx =
8 9 7
idx =
1 3 2
>> [mx,idx] = max(magic(3))(4) % now what?
我们应该从 MAX 中返回每个输出变量的第 4 个元素,还是仅从第一个输出参数中返回第 4 个元素以及完整的第二个输出?当函数返回不同大小的输出时呢?
所有这些仍然适用于其他类型的索引:f()(3)
/ f(3)
、f().x
/ f.x
、f(){3}
/ f{3}
。
正因为如此,MathWorks 决定避免上述所有混淆,并且根本不允许直接对结果进行索引。不幸的是,他们限制了过程中的语法。例如 Octave 没有这样的限制(你可以写magic(4)(1,2)
),但是新的 OOP 系统仍在开发过程中,所以我不知道 Octave 是如何处理这种情况的。
对于那些感兴趣的人,这让我想起了另一个关于包和类以及直接索引以获取属性的类似错误。无论您是从命令提示符、脚本还是 M 文件函数调用它,结果都不同...