コメント
構造体からクラスに切り替えることはできますか? その場合は、構造体を模倣するものを作成し、変更されるたびに stack = dbstack を呼び出してスタックを取得し、変更とともにスタックを保存します。変更を行ったコマンドは、後でスタック内の行番号から自動的に取得できます。
コメントでこれに対するフォローアップ要求として、構造体機能を提供し、その割り当ての記録も保持するクラスの例を次に示します。
classdef utstruct
properties (SetAccess = private)
modifications
end
properties (Dependent, SetAccess = private)
myStruct
end
properties (Access = private)
m_struct
end
methods
function self = utstruct(varargin)
if nargin > 0
self.m_struct = builtin('struct', varargin{:});
else
self.m_struct = builtin('struct');
end
% Should update self.modifications here
end
function B = subsref(self, s)
if any(strcmp(s(1).subs, properties(self)))
B = builtin('subsref', self, s);
else
B = subsref(self.m_struct, s);
end
end
function A = subsasgn(self, s, b)
self.m_struct = subsasgn(self.m_struct, s, b);
newMod = builtin('struct');
newMod.type = 'subsasgn';
newMod.modData = {s b};
newMod.stack = dbstack;
self.modifications = [self.modifications; newMod];
A = self;
end
function disp(self)
disp(self.m_struct);
end
function names = fieldnames(self, varargin)
names = fieldnames(self.m_struct, varargin{:});
end
function C = cat(self, dim, varargin)
uts = cellfun(@(x)isa(x, 'utstruct'), varargin);
varargin{uts} = cellfun(@(x)x.m_struct, varargin(uts));
varargin = [{self.m_struct} varargin];
self.m_struct = cat(dim, varargin{:});
% Should update self.modifications here
C = self;
end
function C = horzcat(self, varargin)
C = self.cat(1, varargin{:});
end
function C = vertcat(self, varargin)
C = self.cat(2, varargin{:});
end
function value = get.myStruct(self)
value = self.m_struct;
end
end
end
初期化/連結操作が発生したときに変更配列を更新するコードを追加する必要があります。
subsref
とのsubsasgn
オーバーライドは、(すべてのアクティビティを実際の構造体に延期することによって) 構造体のように動作させるための重要なポイントですが、他のオーバーライドも同様fieldnames
でdisp
あり、同じことを行います。構造体へのすべての割り当ての記録にはsubsasgn
、割り当てを生成したスタックと共に保持されます。
注:これがビルトインと完全に互換性を持つようにするには、struct
おそらくさらにいくつかのメソッドをオーバーライドする必要がありますが、これで十分です。MATLAB 組み込み型のサブクラス化を参照してください。
編集:例をもう少し堅牢にしました。これは、あるべき値クラスになり、連結で機能します。
編集:struct(...)
関数を再定義することにより、検索と置換を使用して既存の呼び出しをリファクタリングすることを避けることができますstruct
:
function s = struct(varargin)
% STRUCT Overrides default struct function to provide unit-testable structs
%
% Set global variable unitTestStructEnabled to true to enable this
% function.
%
global unitTestStructEnabled;
if isempty(unitTestStructEnabled)
unitTestStructEnabled = false;
end
if unitTestStructEnabled
s = utstruct(varargin{:});
else
s = builtin('struct', varargin{:});
end
最初に構造体を作成するときに警告が表示されるため (オフにすることもできますが、それによって他の問題が隠れる可能性があります)、おそらくそれをパスにずっとぶら下げたくないでしょう。通常はパスにないフォルダーを作成し、単体テスト用のパス ( addpath
/ rmpath
) に一時的に追加します。