Main Content

numArgumentsFromSubscript

基于 subsref 和 subsasgn 的自定义索引的参数数目

说明

此函数支持实现 subsrefsubsasgn 的类的自定义索引。对于在 R2021b 及更高版本中创建的类,建议的自定义索引过程是从 matlab.mixin.indexing.RedefinesParenmatlab.mixin.indexing.RedefinesDotmatlab.mixin.indexing.RedefinesBrace 的某种组合中继承。计算此类型的索引的参数数目的等效函数是 listLength。有关详细信息,请参阅自定义对象索引

示例

n = numArgumentsFromSubscript(obj,s,indexingContext) 返回 subsasgn 的预期输入的数量,或 subsref 的预期输出的数量。

重载 numArgumentsFromSubscript 来描述要从索引表达式返回的值数量,此处的索引表达式是指会返回或赋值给逗号分隔列表的索引表达式。即,以 '{}''.' 索引结束的索引表达式。numArgumentsFromSubscript 函数可以:

  • 访问索引表达式中使用的索引操作和索引。

  • 确定索引操作的发生环境是在引用语句中、传递给函数的表达式中,还是在赋值过程中。

如果某个类重载 numArgumentsFromSubscript,MATLAB® 会调用它来确定索引操作中涉及的数组元素的数量(前提是元素数量大于 1 时)。例如,下面这些 '.' 索引操作会引发对 numArgumentsFromSubscript 的调用:

  • objArray.a - 语句中引用的元素数量 (Statement)

  • func(objArray.a) - 表达式中返回的元素数量 (Expression)

  • [objArray.a] = rhs - 用逗号分隔的列表赋值的值数量 (Assignment)

MATLAB 使用调用上下文来确定何时应用 numArgumentsFromSubscript 返回的值。您实现的 numArgumentsFromSubscript 可以为三种类型的索引语句提供不同的输出。例如,下面这个 numArgumentsFromSubscript 的重载即可实现:

  • 针对传递给函数的索引表达式,更改 subsref 的预期输出参数数量。

  • 使用索引子结构体 s 来确定索引操作所需的参数数量

function n = numArgumentsFromSubscript(obj,s,indexingContext)
   if indexingContext == matlab.mixin.util.IndexingContext.Expression
      n = 1;
   else
      n = length(s(1).subs{:});
   end
end

利用 varargout 输出实现 subsref 方法,以便 MATLAB 能够使用指定的输出参数数量调用此方法。

function varargout = subsref(obj,s)
   ...
end

示例

全部折叠

使用字词作为对象属性的索引。

默认情况下,MATLAB 将字符数组中的每个字符视为一个单独元素。因此,MATLAB 将一个字符数组索引解释为多个索引值。

如果不重载 numArgumentsFromSubscript,则关键字索引语句会为 subsrefsubsasgn 方法请求过多的参数。要实现将字符数组用作单个关键字的索引,请定义 numArgumentsFromSubscript 方法以返回 1 作为引用或赋值的元素数量。

重载 numArgumentsFromSubscript 以支持以下类型的索引引用和赋值。

包含字符数组的索引引用:

obj{'keyword'}

函数参数中的索引引用:

func(obj{'keyword'})

通过逗号分隔的列表为对象数组赋值:

[obj{'keyword'}] = right-side values;

在这些情况下,subsrefsubsasgn 无法确定调用上下文中分别所需的输出和输入参数数量。请使用 numArgumentsFromSubscript 函数提供此信息。

定义包含两个属性的 KeyIndex 类。用 KeyCell 存储键名。用 DataArray 存储相应的数据。要自定义索引,请执行以下操作:

  • 实现 subsref 方法,该方法返回对应于指定关键字的数据值。

  • 实现 subsasgn 方法,该方法将指定的值赋予 DataArray 属性中的相应元素。

  • 重载 numArgumentsFromSubscript 以返回值 1 或标量对象,以及对象数组的 numel(objArray) 的值。

KeyCell 属性指定一个包含月份名称的元胞数组。在 DataArray 属性中,指定包含每一月份所对应降雪量的数值数组。

snow15 = KeyIndex({'Jan','Feb','March'},[36 42 2])
snow15 = 

  KeyIndex with properties:

      KeyCell: {'Jan'  'Feb'  'March'}
    DataArray: [36 42 2]

使用关键字引用特定月份的降雪量:

snow15{'Feb'}
ans =

    42

使用包含关键字的 '{}' 索引赋值给相应的元素:

snow15{'Feb'} = 52;

对应于键 'Feb' 的值会更改:

snow15{'Feb'}
ans =

    52

创建一个包含两个年份的降雪量的数组:

snow14 = KeyIndex({'Jan','Feb','March'},[12 8 2]);
sTotal = [snow14,snow15];

显示这两个年份的二月的降雪量:

sTotal{'Feb'}
ans =

     8


ans =

    52

更新这两个年份的二月份的降雪量值。为元胞数组进行索引将返回一个逗号分隔的列表:

c{1} = 34;
c{2} = 56;
[sTotal{'Feb'}] = c{:};

下面是 KeyIndex 类。此类显示了特殊的编程技巧。它没有包含错误检查和您的类所需的其他功能。

classdef KeyIndex
   properties
      KeyCell
      DataArray
   end
   methods
      function obj = KeyIndex(key,data)
         if nargin > 0
            obj.KeyCell = key;
            obj.DataArray = data;
         end
      end
      function n = numArgumentsFromSubscript(obj,~,~)
         n = numel(obj);
      end
      function varargout = subsref(obj,s)
         a = numel(obj);
         switch s(1).type
            case '{}'
               varargout = cell(1,a);
               for j = 1:a
                  for k = 1:numel(obj(j).KeyCell)
                     if strcmp(s.subs(:),obj(j).KeyCell{k})
                        varargout{j} = obj(j).DataArray(k);
                     end
                  end
               end
            case '.'
               varargout = {builtin('subsref',obj,s)};
            case '()'
               varargout = {builtin('subsref',obj,s)};
         end
      end
      function obj = subsasgn(obj,s,varargin)
         a = numel(varargin);
         switch s(1).type
            case '{}'
               for j = 1:a
                  for k = 1:numel(obj(j).KeyCell)
                     if strcmp(s.subs(:),obj(j).KeyCell{k})
                        obj(j).DataArray(k) = varargin{j};
                     end
                  end
               end
            case '.'
               obj = builtin('subsasgn',obj,s,varargin{:});
            case '()'
               obj = builtin('subsasgn',obj,s,varargin{:});
         end
      end
   end
end

定义一个支持按元素和按数组对属性进行索引的类。

numArgumentsFromSubscript 函数允许类自定义对特定属性的引用。numArgumentsFromSubscript 的索引子结构体参数 (s) 在一个点索引表达式中包含引用的属性名称(即 obj.PropertyName 形式的引用)。使用索引子结构体,numArgumentsFromSubscript 可以为任何给定属性返回一个唯一值。

PerArray 类使用索引子结构体中的信息指定每个属性引用的输出数量。

重载 numArgumentsFromSubscript 以:

  • ByElement 属性返回一个逗号分隔的值列表,每个数组元素对应一个值

  • 为整个数组的 ByArray 属性返回一个单一值

创建 PerArray 对象数组:

for k = 1:4
   pa(k) = PerArray(rand(k));
end

查询 ByElement 属性以返回一个属性值的逗号分隔列表:

pa.ByElement
ans =

    0.7513


ans =

    0.2551    0.6991
    0.5060    0.8909


ans =

    0.9593    0.1493    0.2543
    0.5472    0.2575    0.8143
    0.1386    0.8407    0.2435


ans =

    0.9293    0.6160    0.5853    0.7572
    0.3500    0.4733    0.5497    0.7537
    0.1966    0.3517    0.9172    0.3804
    0.2511    0.8308    0.2858    0.5678

查询 ByArray 属性以为数组返回一个单一值:

pa.ByArray
ans =

    3.1416

下面是 PerArray 类。此类显示了特殊的编程技巧。它没有包含错误检查和您的类所需的其他功能。

classdef PerArray
   properties
      ByElement
   end
   properties (Constant)
      ByArray = pi;
   end
   methods
      function obj = PerArray(be)
         if nargin > 0
            obj.ByElement = be;
         end
      end
      function n = numArgumentsFromSubscript(obj,s,indexingContext)
         import matlab.mixin.util.IndexingContext
         if (indexingContext ~= IndexingContext.Assignment)
            if length(s) < 2
               switch (s.subs(:)')
                  case 'ByElement'
                     n = numel(obj);
                  case 'ByArray'
                     if strcmp(s(1).type,'.')
                        n = 1;
                     end
               end
            elseif length(s) > 1
               n = length([s(1).subs{:}]);
            end
         end
      end
      function varargout = subsref(obj,s)
         
         switch s(1).type
            case '.'
               varargout = cell(1,numel(obj));
               for k = 1:numel(obj)
                  varargout{k} = obj(k).(s.subs(:));
               end
            case '()'
               if length([s(1).subs{:}]) > 1
                  ind = [s(1).subs{:}];
                  numInd = length(ind);
                  varargout = cell(1,numInd);
                  for k = 1:numInd
                     varargout{k} = obj(ind(k)).(s(2).subs(:));
                  end
               else
                  varargout = {builtin('subsref',obj,s)};
               end
         end
      end
   end
end

输入参数

全部折叠

索引操作中使用的重载类的对象。此对象的类用于确定在发生索引操作后, MATLAB 是调用 subsref 还是 subsasgn

包含有关特定索引表达式的信息的索引结构体或索引结构体数组。每个结构体有两个字段:

  • type - 索引表达式可以是 '()''{}''.'

  • subs - 下标值(属性名称或包含索引编号的元胞数组)

数据类型: struct

结果所适用的上下文,指定为以下枚举之一:

  • matlab.mixin.util.IndexingContext.Statement - 索引引用用作语句 (obj.a)

  • matlab.mixin.util.IndexingContext.Expression - 索引引用用作函数的一个参数 (func(obj.a))

  • matlab.mixin.util.IndexingContext.Assignment - 索引赋值 ([obj.a] = x)。

输出参数

全部折叠

重载的 subsref 返回的参数数量或传递给重载的 subsasgn 的参数数量。重载 numArgumentsFromSubscript 以返回各种索引情况下类所需的值。

提示

  • 重载 numArgumentsFromSubscript 而不是 numel,以控制来自重载的 subsrefsubsasgn 的结果。重载 numArgumentsFromSubscript 可以避免重载 numel 导致的错误。

版本历史记录

在 R2015b 中推出