是否可以在Matlab中创建对结构的引用? 表现得像句柄的东西,但本质上是一个结构?
我尝试编写一个继承自handle并包含结构的类,但重新定义subsref和subsasgn是一种痛苦。
例如,我的下面的代码不处理类似的情况 obj(2).D(5)= 77 要么 obj.D.X.Y.Z.P = 1;
有一个简单但不是很优雅的解决方案, 只需将结构“属性”设为公共状态即可获取和设置。
classdef Exchangeable < handle
% This is a class that's essentially a structure or a dictionary.
% attributes is a structure.
% we then redefine the operators for accessing and assigning fields (the .)
properties (SetAccess = protected, GetAccess = public)
attributes;
end % public properties
methods (Access = public)
function self = Exchangeable(attributes_struct)
if nargin == 0 % empty contructor
self.attributes = struct();
else % can pass a structure or another Exchangeable
if isstruct(attributes_struct)
self.attributes = attributes_struct;
elseif isa(attributes_struct, 'Exchangeable')
self.attributes = attributes_struct.attributes;
end
end
end
function display(self)
for k = 1 : numel(self)
fprintf('Exchangeable %d with attributes:\n', k);
disp(self(k).attributes);
end
end
function varargout = subsref(self, s)
% Note that self can be an array, so every case needs to support this.
switch s(1).type
case '.'
if numel(s) == 1 %
% Implement obj.PropertyName
% Note that Ex.Property does not return
% an array. It returns something like a comma-separated list
% This is consistent with Matlab's behaviour.
% Try the same for an array of struct, for example.
f = @(obj) subsref(obj.attributes, s);
varargout = arrayfun(f, self, 'UniformOutput', false);
%varargout = {self.attributes.(s.subs)};% This only works for a single object
else% for example: ee.Spreads(2).Unit
varargout = subsref(self, s(1));
varargout = {subsref(varargout, s(2 : end))};
end
case '()' % obj(ind1 : ind2, :).blabla
varargout = {builtin('subsref', self, s(1))};
if numel(s) == 1
return;
else
varargout = {subsref(varargout{:}, s(2 : end))};
end
case '{}'
error('Exchangeable: {} is not a valid indexing expression');
% if numel(s) == 1
% % Implement obj{indices}
% ...
% elseif numel(s) == 2 && strcmp(s(2).type,'.')
% % Implement obj{indices}.PropertyName
% ...
% else
% % Use built-in for any other expression
% varargout = {builtin('subsref',obj,s)};
% end
otherwise
error('Not a valid indexing expression')
end
end
function self = subsasgn(self, s, varargin)
switch s(1).type
case '.'
if numel(s) == 1
% Implement obj.PropertyName = varargin{:};
% Is there a way to do this via arrayfun?
for k = 1 : numel(self)
self(k).attributes.(s.subs) = varargin{k};
end
elseif numel(s) == 2 && strcmp(s(2).type,'()')
% Implement obj.PropertyName(indices) = varargin{:};
% Only supported for a single object!
assert(numel(self) == 1);
self = builtin('subsasgn', self.attributes, s, varargin{:})
else
% Call built-in for any other case
% FIXME: this is borked
self = builtin('subsasgn', self, s, varargin);
end
case '()'
if numel(s) == 1
% Implement obj(indices) = varargin{:} ;
self = builtin('subsasgn', self, s, varargin{:});
elseif numel(s) > 1% && strcmp(s(2).type,'.')
% Implement obj(indices).PropertyName = varargin{:};
tmp = builtin('subsref', self, s(1));
for k = 1 : numel(tmp)
tmp(k) = subsasgn(tmp(k), s(2 : end), varargin{k})
end
%elseif numel(s) == 3 && strcmp(s(2).type,'.') && strcmp(s(3).type,'()')
% Implement obj(indices).PropertyName(indices) = varargin{:};
%...
end
% case '{}'
% if numel(s) == 1
% % Implement obj{indices} = varargin{:}
% ...
% elseif numel(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 % subsasgn
end % public methods
端