我想要一个包含containers.Map
的课程。另外,我希望能够使用()
索引来访问父类的子映射,例如:
>> map = containers.Map('Foo', 'Bar');
>> ex = Example(map);
>> ex('Foo')
ans =
Bar
此代码如下所示,效果很好。我遇到的唯一问题是在类上定义的其他方法。根据文档,我知道我需要覆盖numArgumentsFromSubscript
(某种程度上?)来帮助nargout
。我在大多数情况下简单地使用numel(obj)
的粗略尝试,但在你调用的函数没有输出参数(在这种情况下为numel(obj) == 1 ~= 0
)时,我没有这样做。
使用下面的示例代码,
>> ex.outGoodbye
ans =
Goodbye
大!然而,
>> ex.sayHello
Error using Example/sayHello
Too many output arguments.
Error in Example/subsref (line 17)
[varargout{1:nargout}] = builtin('subsref', obj, struct);
你怎么解决这个问题?
classdef Example
% =====================================================================
properties
map
end
% =====================================================================
methods
% -----------------------------------------------------------------
function obj = Example(map)
obj.map = map;
end
% -----------------------------------------------------------------
function varargout = subsref(obj, struct)
if strcmp(struct(1).type, '()')
[varargout{1:nargout}] = builtin('subsref', obj.map, struct);
else
[varargout{1:nargout}] = builtin('subsref', obj, struct);
end
end
% -----------------------------------------------------------------
function n = numArgumentsFromSubscript(obj, struct, indexingContext)
n = numel(obj); % Necessary to overload subsref - for some reason
end
% -----------------------------------------------------------------
function obj = subsasgn(obj, struct, varargin)
if strcmp(struct(1).type, '()')
obj = builtin('subsasgn', obj.map, struct, varargin{:});
obj = Example(obj);
else
obj = builtin('subsasgn', obj, struct, varargin{:});
end
end
% -----------------------------------------------------------------
function sayHello(obj)
disp('Hello'); % nargout == 0. Does NOT work
end
% -----------------------------------------------------------------
function out = outGoodbye(obj)
out = 'Goodbye'; % nargout > 0. Works
end
% -----------------------------------------------------------------
end
% =====================================================================
end
答案 0 :(得分:3)
进一步深入研究这个问题,你可以选择一些方法来解决这个问题。
method(obj)
致电会议您可以简单地更改调用类方法的方式。您可以简单地使用标准函数表示法,而不是使用点表示法。
sayHello(ex)
%// vs.
ex.sayHello()
这将避免在调用方法时调用subsref
。而且,这实际上是当前MATLAB的OOP迭代中的类的fastest way to call a method。此外,这不需要更改当前代码。
nargout
确定方法输出数另一种选择是在subsref
或numArgumentsFromSubscript
中添加一个特殊情况,用于查找使用点表示法调用的方法。然后,您可以使用following call到nargout
显式确定方法的输出参数数。
nArgs = nargout('classname>classname.methodname');
然后你会使用它而不是numel(obj)
。这可以在 numArgumentsFromSubscript
或 subsref
中实现。
<强> numArgumentsFromSubscript
强>
function n = numArgumentsFromSubscript(obj, struct, indexingContext)
%// Check if we are calling obj.method
if strcmp(struct(1).type, '.') && ...
ischar(struct(1).subs) && ismember(struct(1).subs, methods(obj))
%// Determine the package (if any)
cls = class(obj);
parts = regexp(cls, '\.', 'split');
%// Import the package (if any) just into the namespace of this method
if numel(parts) > 1
import(cls);
end
%// Determine number of outputs for this method
n = nargout(sprintf('%s>%s.%s', parts{[end end]}, struct(1).subs));
else
%// Default to numel(obj)
n = numel(obj);
end
end
<强> subsref
强>
function varargout = subsref(obj, struct)
if strcmp(struct(1).type, '()')
[varargout{1:nargout}] = builtin('subsref', obj.map, struct);
%// Check if we are calling obj.method
elseif strcmp(struct(1).type, '.') && ...
ischar(struct(1).subs) && ismember(struct(1).subs, methods(obj))
%// Determine the package (if any)
cls = class(obj);
parts = regexp(cls, '\.', 'split');
%// Import the package (if any) just into the namespace of this method
if numel(parts) > 1
import(cls);
end
%// Determine number of outputs for this method
nout = nargout(sprintf('%s>%s.%s', parts{[end end]}, struct(1).subs));
%// Call builtin subsref with this number of outputs
[varargout{1:nout}] = builtin('subsref', obj, struct);
else
[varargout{1:nargout}] = builtin('subsref', obj, struct);
end
end
subsref
是一种痛苦,很多时候你最终会有很多逻辑来确定被调用的内容,而且你只会在80%的时间内做对。我认为第一种方法是最直接的,可能是性能最高的(你跳过subsref
中的所有检查)并且更好地处理对象数组。
如果您真的想保留obj.method
符号,我建议您更改numArgumentsFromSubscript
(而不是subsref
)以将输出参数的数量保留在一个位置。
<强>更新强>
根据您的反馈,nargout
技巧在包含在包(foo.bar.Example
)中的情况下不起作用。我在上面的例子中添加了一个解决方法。诀窍是在致电import('foo.bar.Example')
之前致电nargout('Example>Example.sayHello')
。