subsref - 如何通过对象名称属性索引到对象数组

问题描述 投票:0回答:1

我在 Matlab 中有一个简单的类:

classdef DummyClass
    properties
        name = '';
        value = nan;
    end
    methods
        function obj = DummyClass(varargin)
            if nargin > 0
                obj.name = varargin{1};
                if nargin > 1
                    obj.value = varargin{2};
                end
            end
        end
    end
end

我定义了一个 DummyClass 对象数组,然后调用 name 属性:

t1(1) = DummyClass("a1", 1);
t1(2) = DummyClass("a2", 2);
t1.name

结果是:

ans = 

    "a1"


ans = 

    "a2"

我的最终目标是能够使用“name”属性作为对象的输入参数来访问“value”属性。例如,

t1("a1")
应返回 1。

作为第一步,我在 DummyClass 中添加 subsref 方法:

classdef DummyClass
    properties
        name = '';
        value = nan;
    end
    methods
        function obj = DummyClass(varargin)
            if nargin > 0
                obj.name = varargin{1};
                if nargin > 1
                    obj.value = varargin{2};
                end
            end
        end
        function out = subsref(obj, S)
            out = 1;
        end
    end
end

当我现在尝试使用 t1.name 访问 name 属性时,它会给出错误(请注意,它没有提及发生错误的行)

” 使用索引时出错 输出参数太多。”

显然 subsref 不能处理对象数组。我该如何修改它才能使后者成为可能?

我尝试使用 subsasgn 代替,但也没有成功(请参阅 stackoverflow 中的类似问题

matlab class oop
1个回答
0
投票

知道你想要做什么,我建议保留你的基类不变,并在容器类中处理你想要的功能。

使用尽可能简单的基本示例类:

classdef DummyClass
    properties
        name = '';
        value = nan;
    end
    
    methods
        function obj = DummyClass(varargin)
            if nargin > 0
                obj.name = varargin{1};
                if nargin > 1
                    obj.value = varargin{2};
                end
            end
        end    
    end
end

您可以构造一个容器类,它将保存这些数组,并根据您感兴趣的情况调整

subsref()
函数:

classdef DummyClassArray < handle
    properties
        dummies (:,1) DummyClass
    end
    methods
        function obj = DummyClassArray()
        end
        
        function obj = AddDummy(obj,dc)
            obj.dummies(end+1,1) = dc ;
        end
        
        function varargout = subsref(obj,s)
            %     [varargout{1:nargout}] = builtin('subsref',obj,s) ;
            
            switch s(1).type
                case '.'
                    [varargout{1:nargout}] = builtin('subsref',obj,s);
                    
                case '()'
                    if length(s) == 1
                        % if the parameter is an numeric index => return value at specified index
                        % if the parameter is a string => return value at matching name
                        p = s.subs{1} ;
                        if isnumeric(p)
                            [varargout{1:nargout}] = find_dummy_by_index(obj, p) ;
                        elseif ischar(p) || isstring(p)
                            [varargout{1:nargout}] = find_dummy_by_name(obj,p) ;
                        end
                        
                    else
                        % Use built-in for any other expression
                        [varargout{1:nargout}] = builtin('subsref',obj,s);
                    end
                    
                case '{}'
                    [varargout{1:nargout}] = builtin('subsref',obj,s);
                    
                otherwise
                    error('Not a valid indexing expression')
            end
        end
        
        function out = find_dummy_by_name(obj, name2find)
            n = numel(obj.dummies);
            out = [] ;
            for k=1:n
                if strcmpi(obj.dummies(k).name, name2find)
                    out = obj.dummies(k).value ;
                    break
                end
            end
        end
        
        function out = find_dummy_by_index(obj, idx2find)
            % This is just to make sure the provided index is not out of
            % bound
            n = numel(obj.dummies);
            if idx2find <= n
                out = obj.dummies(idx2find).value ;
            else
                out = [] ; % Probably wise to throw an error here
            end
        end
        

    end
end

有了它,您现在可以通过指定关联的

value
来访问任何
name
属性:

% build the base example objects
t1(1) = DummyClass("a1", 10);
t1(2) = DummyClass("a2", 20);

% instanciate and populate the container array
dca = DummyClassArray ;
dca.AddDummy(t1(1)) ;
dca.AddDummy(t1(2))

ans = 
  DummyClassArray with properties:

    dummies: [2×1 DummyClass]

现在:

>> dca("a1")
ans =
    10
>> dca(2)
ans =
    20
>> dca.dummies
ans = 
  2×1 DummyClass array with properties:

    name
    value

现在类容器实际上已经是准系统来说明功能了。为了增加使用类容器的稳健性和舒适性,您应该:

  • 改进构造函数,允许您直接发送基类作为输入,甚至是基类数组(因此您不必将它们一一添加)。
  • 实施一些输入检查(如果处理数组,则针对数据类型和索引)
  • 可能以同样的方式修改
    subassign
    ,这样您也可以修改一个值(通过使用其名称进行索引)。例如:
    dca("a1")=42;
© www.soinside.com 2019 - 2024. All rights reserved.