Как получить статические переменные-члены в классах MATLAB?

Есть ли способ определить статические переменные-члены в классах MATLAB?

Это не работает:

classdef A

    properties ( Static )
        m = 0;
    end
end

Предлагается использовать ключевое слово "Constant" вместо "Static", свойства константы не могут быть изменены. Я хочу переменную, общую для всех объектов класса A, и я хочу иметь возможность модифицировать эту переменную в методах класса A.

Итак, мне нужна приватная переменная-член. Есть ли способ получить его в MATLAB?


Обнаружено, что обходной путь может быть выполнен с использованием постоянных переменных в статических функциях-членах.

В этом случае вы должны наследовать все свои классы из базового класса следующим образом.

classdef object < handle

    properties ( GetAccess = 'public', SetAccess = 'private' )
        id
    end

    methods ( Access = 'protected' )
        function obj = object()
            obj.id = object.increment();
        end
    end

    methods ( Static, Access = 'private' )
        function result = increment()
            persistent stamp;
            if isempty( stamp )
                stamp = 0;
            end
            stamp = stamp + uint32(1);
            result = stamp;
        end
    end  
end

Ответы

Ответ 1

Вы не можете, это по дизайну. Вы должны использовать переменную persistent (технику из MATLAB в 1980 году, применяемую в 2011 году)!

Для полноты я должен упомянуть, что на самом деле существует с 2010b недокументированный и, возможно, не поддерживаемый модификатор свойства static.

Для фона см. здесь ответ Дэйв Фоти, Менеджер группы MATLAB OO:

В MATLAB классы могут определять константу свойства, но не "статические" свойства в смысле других такие языки, как С++. Были бета-версии релизы, которые "Статические" свойства и недокументированный атрибут остается тогда. Однако атрибут Static недокументированные, не должны использоваться, и скорее всего, будут удалены в будущем Релиз MATLAB. R2008a реализует его как синоним Constant и обеспечивает нет дополнительной функциональности документированное поведение Constant свойства.

Постоянные свойства не могут быть изменены от начального значения, указанного в объявление собственности. Есть несколько причин, почему MATLAB работает как он это делает. Во-первых, MATLAB давние правила, что переменные всегда превалировать над именами функций и классов, и что присваивания переменная, если ее еще нет. Таким образом, любое выражение вида "A.B = C" вводит новую переменную A, являющуюся структурным массивом, содержащим поле B, значение которого равно C. Если "A.B = C" может относиться к статическому свойству класс А, тогда класс А прецедент над переменной A и этот будет очень значительным несовместимость с предыдущими выпусками MATLAB. Это означало бы, что m файл, содержащий задание утверждение "A.B = C" может иметь значение изменено введением класса A где-то на MATLAB путь. Программисты MATLAB имеют всегда можно было полагаться на назначение операторы, вводящие переменные тень любого другого использования с тем же именем.

Во-вторых, мы заметили, что статические данные редко используются в других классах за исключением частных данных в пределах класса или как общедоступные константы. Для Например, обзор нескольких Java библиотеки классов обнаружили, что все общедоступные статические поля также были окончательными. В MATLAB, константные свойства могут быть используется как "публичный конечный статический" полей в Java. Для внутренних данных класса, MATLAB уже имеет постоянные переменные, которые могут быть созданы внутри частных или защищенных методов или локальные функции, используемые класс. Есть также веские основания для избегать статических данных в MATLAB, где возможное. Если класс имеет статические данные, это может быть трудно использовать класс в нескольких приложениях потому что статические данные могут быть источником конфликтов среди Приложения. На некоторых других языках, это не проблема, потому что разные приложения отдельно скомпилирован в исполняемые файлы, запущенные в разные процессы с разными копии статических данных класса. В MATLAB, часто много разных приложения могут выполняться в тот же процесс и окружающая среда с единственная копия каждого класса.

Ответ 2

Вот прямой способ создания статического свойства в Matlab. Единственная разница между этой реализацией и гипотетическим (но невозможным, см. Ответ Михаила) истинным статическим свойством - это синтаксис для установки переменной-члена.

classdef StaticVarClass
    methods (Static = true)
        function val = staticVar(newval)
            persistent currentval;
            if nargin >= 1
                currentval = newval;
            end
            val = currentval;
        end
    end
end

Теперь статическое свойство staticVar может быть прочитано через:

StaticVarClass.staticVar

... и установить через:

StaticVarClass.staticVar(newval);

Так, например, это ожидаемый результат теста этой функции:

>> StaticVarClass.staticVar
  ans =
      []
>> StaticVarClass.staticVar('foobar')
  ans =
      foobar
>> StaticVarClass.staticVar
  ans =
      foobar
>> 

Этот подход работает так же хорошо для частных статических свойств, как вы просили, но демонстрационный код немного дольше. Обратите внимание, что это не класс дескриптора (хотя он отлично работает и с классом дескриптора).

classdef StaticVarClass
    methods (Access = private, Static = true)
        function val = staticVar(newval)
            persistent currentval;
            if nargin >= 1
                currentval = newval;
            end
            val = currentval;
        end
    end

    methods
        function this = setStatic(this, newval)
            StaticVarClass.staticVar(newval);
        end

        function v = getStatic(this)
            v = StaticVarClass.staticVar;
        end
    end
end

... и тест:

>> x = StaticVarClass
  x = 
      StaticVarClass with no properties.
      Methods
>> x.getStatic
  ans =
      []
>> x.setStatic('foobar')
  ans = 
      StaticVarClass with no properties.
      Methods
>> x.getStatic
  ans =
      foobar
>> 

Ответ 3

(просто чтобы сообщить) существует (другой?) способ создания статических данных в matlab

предположим, что у вас есть класс "handle", его имя - "автомобиль", если вы хотите, чтобы класс автомобиля имел статические данные, вы могли бы построить другой класс дескриптора и использовать его в композиции броска класса автомобиля, последний класс работает как статические данные для класса автомобилей

classdef car<handle 
    properties 
         static_data:STATIC_DATA_HOLDER;
    end
end

classdef STATIC_DATA_HOLDER<handle
    properties
        data
    end
end

таким образом, когда вы создаете первый экземпляр класса автомобиля, будет создан экземпляр STATIC_DATA_HOLDER, и когда вы создадите второй экземпляр класса автомобилей, он использует ранее созданный класс STATIC_DATA_HOLDER.

этот код протестирован с помощью "MATLAB 2013b"

Ответ 4

Другим обходным решением, чтобы получить что-то вроде статических свойств, является использование того факта, что код инициализации для переменных-членов выполняется только один раз, когда загружается файл класса. Это означает, что если у вас есть определение типа

classdef foo
    properties
        stuff = some_function()
    end
end

то some_function вызывается только один раз, и если он возвращает объект типа класса, он будет использоваться всеми экземплярами. Я добавил пример реализации, который показывает, как это можно использовать:

classdef ClassWithStaticMembers
    properties
        classvars = StaticVarContainer('foo', 0, 'bar', 2);
        othervar
    end
    methods
        function obj=ClassWithStaticMembers(var)
            obj.othervar = var;
        end
    end 
end

classdef StaticVarContainer < dynamicprops
    methods
        function obj=StaticVarContainer(varargin)
            for i=1:2:numel(varargin)
                obj.addprop(varargin{i});
                obj.(varargin{i}) = varargin{i+1};
            end
        end
    end
end

Если вы запустите этот пример кода

obj1 = ClassWithStaticMembers(3);
obj2 = ClassWithStaticMembers(5);
obj1.classvars.foo = [2,3];

obj1.othervar
obj1.classvars

obj2.othervar
obj2.classvars

вы увидите, что classvars действительно разделяется. Я думаю, что это решение намного лучше, чем использование постоянных переменных в функциях, так как вы можете повторно использовать StaticVarContainer так часто, как хотите, его проще в использовании, и, кроме того, вы непосредственно видите инициализацию статических переменных в разделе свойств.

Чтобы получить результат, который требуется в вопросе OP (т.е. для реализации счетчика объектов), общее свойство может быть сделано Constant, так что на него можно ссылаться без соответствующего экземпляра:

classdef ClassWithCounter
    properties (Constant)
        static = StaticVarContainer('counter', 0);
    end
    methods
        function obj=ClassWithCounter()
            obj.static.counter = obj.static.counter + 1;
        end
    end 
end

clear all
obj1 = ClassWithCounter();
obj2 = ClassWithCounter();
obj3 = ClassWithCounter();

ClassWithCounter.static.counter

Обратите внимание, что атрибут Constant означает только то, что, например, obj1.static не может быть изменен, но он не влияет на obj1.static.counter, который не является постоянным и может быть настроен на желание сердца.