假设a
定义为下面的结构。我试图找到与 R 的 dput 等效的命令,但在这里出错。例如,我知道下面的内容必须是这种形式struct('const',1,'terms',{{struct(),struct()}})
,但我不知道结构中存储了什么,而无需使用类似here的命令进行检查,这很耗时。
那么通过哪个命令我可以看到在 Matlab 中生成结构的原始命令?
>> a
a =
const: 1
terms: {[1x1 struct] [1x1 struct]}
评论
您是否可以从使用结构切换到类?如果是这样,您可以制作一个模仿该结构的结构,并且每次对其进行修改时调用 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
)。
这是一个函数的骨架dumpvar
,即沿着tashuhka的想法
function str = dumpvar(a)
switch class(a)
case 'double'
if isempty(a)
str = '[]'; % bug when "a" is multidimensional and empty
elseif isscalar(a)
str = num2str(a);
elseif isrow(a)
str = strcat('[', dumpvar(a(1)));
for k = 2:size(a,2)
str = strcat(str,',',dumpvar(a(k)));
end;
str = strcat(str, ']');
elseif numel(size(a)) == 2
str = strcat('[', dumpvar(a(1,:)));
for k = 2:size(a,1)
str = strcat(str,';',dumpvar(a(k,:)));
end;
str = strcat(str, ']');
else
do_what_i_mean();
end;
case 'struct'
fn = fieldnames(a);
if isempty(fn)
str = 'struct()';
elseif isscalar(a)
str = strcat('struct(''', fn{1},''',', dumpvar(a.(fn{1})));
for k=2:numel(fn)
str = strcat(str,',''',fn{k},''',', dumpvar(a.(fn{k})));
end;
str = strcat(str, ')');
else
do_what_i_mean();
end;
otherwise
do_what_i_mean();
end;
function do_what_i_mean()
throwAsCaller(MException(...
'beingLazy:onSaturday:Fault', ...
'Storage of class "%s" and arity %d is not implemented yet. Would you?', ...
class(a), numel(size(a))...
));
end;
end
将其保存dumpvar.m
在 Matlab 路径中某处的文件中,然后使用以下代码片段对其进行测试:
a = struct(...
'field1', 1,...
'field2', [],...
'field10', struct(...
'field3', [1 2;2 3;3 4],...
'field4', struct()...
)...
);
disp(dumpvar(a));
eval(sprintf('b=%s;', dumpvar(a)));
请注意,此函数仍处于玩具阶段:它几乎是穷尽的(缺乏对结构数组、单元格、字符、逻辑和其他基本类型的处理,更不用说用户定义的类 --- 呵呵,那些将是一个泡菜) 并且它意味着由您使用您需要的任何功能来完成。
虽然它不能完全回答您的问题,但 Urs 的vsize()可以帮助您:
% Create some complicated variable
v(1).a{1}=sparse(magic(3)+2i*magic(3));
v(2).a{2}={struct('FA',{'a','bb'},'FB',{magic(5),{}})};
v(2).b{2}=@(x) sind(x);
% Dissect
P = vsize(v);
% -------------------------
% 1998 1998 B * v = 2:1x2:struct.(2)
% CELL ----- 360 B v[].a = 2:1x1:cell
% 1750 248 B - v[].a{} = 2:3x3:double.sparse.complex
% CELL ----- 1014 B v[].a = 2:1x2:cell
% 1750 0 B - v[].a{} = 2:0x0:double
% CELL ----- 894 B v[].a{} = 2:1x1:cell
% STRUCT --- 782 B v[].a{}{} = 2:1x2:struct.(2)
% 1748 2 B - v[].a{}{}[].FA = 2:1x1:char
% 1744 4 B - v[].a{}{}[].FA = 2:1x2:char
% 1544 200 B - v[].a{}{}[].FB = 2:5x5:double
% CELL ----- 0 B v[].a{}{}[].FB = 2:0x0:cell
% 1544 0 B - v[].b = 2:0x0:double
% CELL ----- 152 B v[].b = 2:1x2:cell
% 1544 0 B - v[].b{} = 2:0x0:double
% 1512 32 B - v[].b{} = 2:1x1:function_handle