В репозитории Mathworks File Exchange есть несколько реализаций хеш-класса или словарного класса. Все, что я рассмотрел, использует перегрузку скобок для ссылки на ключ, например,
d = Dict;
d('foo') = 'bar';
y = d('foo');
, который кажется разумным интерфейсом. Однако было бы предпочтительнее, если вы хотите легко иметь словари, содержащие другие словари, использовать скобки {}
вместо скобок, поскольку это позволяет обойти синтаксическое ограничение MATLAB (кажется, произвольное), что множественные скобки не являются разрешено, но допускается несколько фигурных скобок, например
t{1}{2}{3} % is legal MATLAB
t(1)(2)(3) % is not legal MATLAB
Так что, если вы хотите легко вкладывать словари в словари,
dict{'key1'}{'key2'}{'key3'}
, так как это обычная идиома в Perl и возможна и часто полезна в других языках, включая Python, тогда, если вы не хотите использовать n-1
промежуточные переменные для извлечения словарной записи на глубину n
слоев, это кажется хорошим выбором. И было бы легко переписать операции класса subsref
и subsasgn
, чтобы сделать то же самое для {}
, как они делали ранее для ()
, и все должно работать.
За исключением случаев, когда я это пробую.
Вот мой код. (Я сократил его до минимального значения. Здесь не реализован настоящий словарь, каждый объект имеет один ключ и одно значение, но этого достаточно, чтобы продемонстрировать проблему.)
classdef TestBraces < handle
properties
% not a full hash table implementation, obviously
key
value
end
methods(Access = public)
function val = subsref(obj, ref)
% Re-implement dot referencing for methods.
if strcmp(ref(1).type, '.')
% User trying to access a method
% Methods access
if ismember(ref(1).subs, methods(obj))
if length(ref) > 1
% Call with args
val = obj.(ref(1).subs)(ref(2).subs{:});
else
% No args
val = obj.(ref.subs);
end
return;
end
% User trying to access something else.
error(['Reference to non-existant property or method ''' ref.subs '''']);
end
switch ref.type
case '()'
error('() indexing not supported.');
case '{}'
theKey = ref.subs{1};
if isequal(obj.key, theKey)
val = obj.value;
else
error('key %s not found', theKey);
end
otherwise
error('Should never happen')
end
end
function obj = subsasgn(obj, ref, value)
%Dict/SUBSASGN Subscript assignment for Dict objects.
%
% See also: Dict
%
if ~strcmp(ref.type,'{}')
error('() and dot indexing for assignment not supported.');
end
% Vectorized calls not supported
if length(ref.subs) > 1
error('Dict only supports storing key/value pairs one at a time.');
end
theKey = ref.subs{1};
obj.key = theKey;
obj.value = value;
end % subsasgn
end
end
Используя этот код, я могу назначить как положено:
t = TestBraces;
t{'foo'} = 'bar'
(И ясно, что назначение работает с вывода дисплея по умолчанию для t
.) Так что subsasgn
, кажется, работает правильно.
Но я не могу получить значение (subsref
не работает):
t{'foo'}
??? Error using ==> subsref
Too many output arguments.
Сообщение об ошибке не имеет смысла для меня, и точка останова на первой исполняемой строке моего обработчика subsref
никогда не срабатывает, поэтому, по крайней мере, внешне это выглядит как проблема MATLAB, а не ошибка в моем коде.
Явно строковые аргументы ()
в скобках разрешены , так как это работает нормально, если вы измените код для работы с ()
вместо {}
. (За исключением того, что вы не можете вложить вложенные операции, которые являются целью упражнения.)
Буду признателен за понимание того, что я делаю неправильно в моем коде, за любые ограничения, которые делают невозможным то, что я делаю, или за альтернативные реализации вложенных словарей.