Main Content

マッピング クラスの小かっこインデックスのカスタマイズ

この例では、クラスの小かっこインデックスをカスタマイズする方法を説明します。MyMap クラスは、cell 配列の要素 ("値") に関連付けられた string ("キー") を格納します。このクラスは matlab.mixin.indexing.RedefinesParen から継承され、小かっこを使用したインデックスのカスタム動作を定義します。このクラスは、次の 3 つのカスタマイズされたインデックス演算をサポートします。

  • instanceName("keyName") は、キーに関連付けられた値を返します。

  • instanceName("keyName") = value は、新しいキーとそれに関連付けられた値を追加します。

  • instanceName("keyName") = [] は、キーとそれに関連付けられた値を削除します。

クラスとその補助関数 validateKeys の完全なコードは、この例の最後に示します。

MyMap クラス説明
classdef MyMap... 
  < matlab.mixin.indexing.RedefinesParen

MyMapRedefinesParen のサブクラスとして定義し、その抽象メソッドを実装します。

properties (Access = private)
   Keys (:,1) string
   Values (:,1) cell
end

プライベート プロパティ Keys および Values は、n 行 1 列のベクトルです。

methods (Static, Access = public)
   function obj = empty(varargin)
      if nargin == 0
         obj = MyMap(string.empty(0,1),cell.empty(0,1));
         return;
      end
            
      keys = string.empty(varargin{:});
      if ~all(size(keys) == [0, 1])
         error("MyMap:MustBeEmptyColumnVector",...
            "The only supported empty size is 0x1.");
      end
            
      obj = MyMap(keys,cell.empty(varargin{:}));
   end
end

キーと値のいずれも含まない MyMap オブジェクトを作成する静的な抽象メソッド empty の実装。

methods (Access = public)
   function obj = MyMap(keys_in,values_in)
      if nargin == 0
         obj = MyMap.empty(0,1);
         return;
      end
            
      narginchk(2,2);
            
      if ~all(size(keys_in) == size(values_in))
         error("MyMap:InputSizesDoNotMatch",...
            "The sizes of the input keys and values must match.");
      end
            
      obj.Keys = keys_in;
      obj.Values = values_in;
   end
end

コンストラクターはキーと値を入力引数として受け入れ、配列が同じサイズであることを確認します。

   function keys = getKeys(obj)
      keys = obj.Keys;
   end
        
   function values = getValues(obj)
      values = obj.Values;
   end

2 つのパブリック メソッドは、キーと値への読み取りアクセスを提供します。

   function varargout = size(obj,varargin)
      [varargout{1:nargout}] = size(obj.Keys,varargin{:});
   end

   function C = cat(dim,varargin)
      error("MyMap:ConcatenationNotSupported",...
         "Concatenation is not supported.");
   end

   function lastKey = end(~,~,~)
       error("MyMap:EndNotSupported",...
          "Using end with MyMap objects is not supported.");"
   end

抽象メソッド sizecat、および end の実装。この例では、catend はサポートされません。

methods (Access = private)
    function [keyExists,idx] = convertKeyToIndex(obj,keyCellArray)
       arguments
          obj
          keyCellArray cell {validateKeys}
       end

       requestedKey = keyCellArray{1};
       idx = find(contains(obj.Keys,requestedKey));
       keyExists = ~isempty(idx);
    end
end

parenReferenceparenAssignparenDelete、および parenListLength メソッドは convertKeyToIndex 補助メソッドを使用します。convertKeyToIndexvalidateKeys を使用して、keyCellArray にキーが 1 つだけ含まれていることを確認します。(クラスの最後の後にある validateKeys のコードを参照してください。) convertKeyToIndex は入力キーの有無を示す logical 値を返し、キーが存在する場合は、そのキーのインデックスを返します。

methods (Access = protected)
   function varargout = parenReference(obj,indexOp)      
      [keyExists,idx] = convertKeyToIndex(obj,indexOp(1).Indices);

      if ~keyExists
         error("MyMap:KeyDoesNotExist",...
            "The requested key does not exist.");
      end

      if numel(indexOp) == 1
         nargoutchk(0,1);
         varargout{1} = obj.Values{idx};
      else
         % Additional operations
         [varargout{1:nargout}] = obj.Values{idx}.(indexOp(2:end));
      end
   end

instanceName("keyName") 形式の参照インデックス式を処理する抽象メソッド parenReference の実装。このメソッドは、IndexingOperation インスタンスを入力として受け取ります。そのインタンス indexOp には、インデックス付けタイプ (この例では小かっこ) と、解釈されている式からのインデックス値が含まれます。parenReferenceindexOp のインデックスを convertKeyToIndex に渡してそのキーの有無を検証し、それが存在する場合は、そのキーのインデックス idx を返します。その後、メソッドはそのキーに対応する値を返します。indexOp に複数のインデックス演算がある場合、"Additional operations" というラベルの付いた行で、これらの演算の処理が MATLAB® に転送されます。

   function obj = parenAssign(obj,indexOp,varargin)
      indicesCell = indexOp(1).Indices;
      [keyExists,idx] = convertKeyToIndex(obj,indicesCell);

      if numel(indexOp) == 1
         value = varargin{1};
         if keyExists
            obj.Values{idx} = value;
         else
            obj.Keys(end+1) = indicesCell{1};
            obj.Values{end+1} = value;
         end
         return;
      end

      if ~keyExists
         error("MyMap:MultiLevelAssignKeyDoesNotExist", ...
            "Assignment failed because key %s does not exist",...
               indicesCell{1});
      end

      [obj.Values{idx}.(indexOp(2:end))] = varargin{:};
   end

instanceName("keyName")= value 形式の代入インデックス式を処理する抽象メソッド parenAssign の実装。参照されているキーが存在する場合、メソッドによって式の右辺からそのキーへ値が代入されます。キーが存在せず、インデックス付けのレベルが 1 つのみの場合、キーと値がリストに追加されます。

   function obj = parenDelete(obj,indexOp)
      [keyExists,idx] = convertKeyToIndex(obj,indexOp(1).Indices);
      if keyExists
         obj.Keys(idx) = [];
         obj.Values(idx) = [];
      else
         error("MyMap:DeleteNonExistentKey",...
            "Unable to perform deletion. The key %s does not exist.",...
            indexOp(1).Indices{1});
      end
   end

instanceName("keyName") = [] 形式の削除インデックス式を処理する抽象メソッド parenDelete の実装。参照されているキーが存在する場合、メソッドによってキーとそれに関連付けられた値が削除されます。キーが存在しない場合、エラーが発生します。

  function n = parenListLength(obj,indexOp,indexingContext)
    [keyExists,idx] = convertKeyToIndex(obj,indexOp(1).Indices);
    if ~keyExists
      if indexingContext == matlab.indexing.IndexingContext.Assignment
         error("MyMap:MultiLevelAssignKeyDoesNotExist", ...
            "Unable to perform assignment. Key %s does not exist",...
               indexOp(1).Indices{1});
      end
      error("MyMap:KeyDoesNotExist",...
         "The requested key does not exist.");
    end   
    n = listLength(obj.Values{idx},indexOp(2:end),indexingContext);
  end
end

小かっこインデックス式から返す値の数を決定する抽象メソッド parenListLength の実装。このメソッドは matlab.indexing.IndexingContext のインスタンスを入力として受け取ることで、参照の使用がステートメント内なのか、関数の引数のリストとしてなのか、または代入演算内なのかを判別します。

 クラスと補助関数コードの展開

MyMapvalidateKeys のコードを MATLAB パスに保存します。3 つのキーと値の初期リストをもつ MyMap のインスタンスを作成します。

map = MyMap(["apple","cherry","orange"],{1,3,15});

map("keyName") 構文を使用して、特定のキーに対応する値を返します。

map("cherry")
ans =

     3

map("keyName") = value を使用して、新しいキーを配列に追加します。

map("banana") = 2;
map("banana")
ans =

     2

map("keyName") = [] を使用して、キーとそれに関連付けられた値を配列から削除します。キーが既に配列内にないことを確認します。

map("orange") = [];
map("orange")
Error using MyMap/parenReference (line 88)
The requested key does not exist.

参考

|