引用结构或如何重新定义subsref和subsagn

时间:2016-03-17 00:10:46

标签: matlab

是否可以在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

0 个答案:

没有答案
相关问题