Почему слишком много выходных аргументов при определении метода подкласса MATLAB container.Map с 0 выходными данными?

Я пытаюсь расширить класс MATLAB container.Map, создав его подкласс и добавив дополнительный метод с 0 выходными данными, но при выполнении метода я сталкиваюсь с ошибкой «слишком много выходных аргументов». Это не относится к новой реализации метода — любой дополнительный метод, который расширяет container.Map() с 0 выходными данными, будет генерировать эту ошибку.

В частности, ошибка возникает при выполнении,

obj = Containers();
obj.testfun();

Для следующего определения класса

classdef Containers < handle & containers.Map
    methods       
        % Test function to display keys.
        function testfun(obj)
            obj.keys(); % dumby thing to execute with incoming object.
            disp('it works!');
        end
    end
end

Однако, если мы немного изменим его, чтобы вывести хотя бы один аргумент,

classdef Containers < handle & containers.Map
    methods       
        % Test function to display keys.
        function dumby = testfun(obj)
            obj.keys();
            disp('it works!')
            dumby = 1;
        end
    end
end

Он будет выполняться правильно. Ошибка появляется именно при создании подкласса container.Map. Если это имеет значение, я использую MATLAB R2014b. Любые предложения относительно того, как решить эту проблему?


person Eric    schedule 22.03.2015    source источник
comment
Вероятно, что-то не работает с функцией subsref или чем-то подобным. Поскольку containers.Map является закрытым исходным кодом, я бы связался с поддержкой mathworks по этому поводу.   -  person Daniel    schedule 22.03.2015


Ответы (1)


Не пытайтесь создать подкласс containers.Map. Это всего лишь мое мнение, но MathWorks должен был сделать это Sealed, чтобы вы просто не смогли.

Здесь происходит следующее: когда вы вводите a.b, или a(b), или a{b}, это преобразуется в вызов метода subsref. Все объекты имеют этот метод. См. doc subsref для более подробной информации о том, как именно MATLAB вызывает subsref, но имейте в виду - это довольно сложно.

Теперь, если вы хотите настроить поведение своего класса, вы можете перегрузить subsref, предоставив свою собственную реализацию. containers.Map делает это, так как ему нужно поддерживать индексацию по ключам, что не характерно для других классов MATLAB.

Я не могу точно сказать, как реализован subsref для containers.Map, так как это встроенный класс, поэтому я не вижу кода. Но я предполагаю, судя по поведению, которое вы здесь видите, что в какой-то момент он пытается выяснить, является ли .testfun() вызовом метода testfun, свойства testfun, поля testfun или чего-то еще, и один из того, что он делает, - это видеть, вызывается ли он с выходными аргументами и соответствующим образом меняет свое поведение.

Это отличный пример того, как вы не можете создать подкласс объекта, не зная (и, возможно, изменяя) его внутренности, поэтому я полагаю, что MathWorks лучше сделать это Sealed, чтобы вы не пытались. В любом случае вы не сможете подклассировать его с желаемым поведением без нескольких обходных путей (например, реализации собственного перегруженного класса subsref для вашего класса Containers, чтобы заставить его работать так, как вы хотите) и немного реверс-инжиниринг (т. е. повторное угадывание внутренностей метода subsref из containers.Map).

Вместо этого вы можете попробовать использовать шаблон адаптера, создав свой собственный класс с containers.Map в качестве частного (возможно, скрытого) свойства, а затем реализовав методы и свойства, которые просто передают свои аргументы и выходные данные базовому containers.Map. Наконец, реализуйте и свои собственные методы.

person Sam Roberts    schedule 23.03.2015
comment
Спасибо, это ясно. Вы правы, утверждая, что он должен быть запечатан. Я столкнулся с другими странными проблемами, подобными этой, когда пытался написать дополнительные методы для container.Map. Например, container.Map также должен перегружать () ссылки, потому что я не мог сделать a(key) = val внутри новых методов. Вместо этого мне пришлось напрямую использовать subsasgn. - person Eric; 23.03.2015
comment
Да, ()-ссылка обрабатывается subsref так же, как и ,-ссылка. - person Sam Roberts; 23.03.2015
comment
PS У меня есть небольшое открытие, которое может вам помочь. Использование вашей нерабочей реализации Containers, хотя obj.testfun выдает ошибку, использование testfun(obj) — нет. Я считаю, что этот второй синтаксис отправляет непосредственно методу, а не через subsref. - person Sam Roberts; 23.03.2015
comment
PPS С другой стороны, вам не нужно наследовать от handle, так как containers.Map уже является handle. - person Sam Roberts; 23.03.2015
comment
Моя мотивация для расширения container.Map() состояла в том, чтобы добавить методы getVal и setVal, чтобы я мог использовать файлы . (точечная) нотация с контейнерами контейнеров глубины 2 без необходимости создавать временные переменные между ними для достижения второй глубины, например. что-то вроде a = Containers(); a(key1) = Containers(); a(key1).setVal(key2, val); для настройки, затем val = a(key1).getVal(key2) для получения. Вместо b(key2) = val; a(key1) = b; для установки и b = a(key1); val = b(key2) для получения. Итак, я ценю то, что вы нашли обходной путь, но он противоречит той тонкости, которую я хотел добавить. - person Eric; 23.03.2015
comment
Мой обходной путь, который сохраняет мое мнение о том, что является тонкостью, заключается в том, чтобы метод выдавал тупую переменную. Поэтому, если я вызываю obj.setVal(key, val), внутри метода он устанавливает dumby = true и возвращает его. - person Eric; 23.03.2015