如何在MATLAB中创build枚举types?
在MATLAB中有枚举types吗? 如果不是,还有什么select?
您可以使用新式的MATLAB类获得一些function:
classdef (Sealed) Colors properties (Constant) RED = 1; GREEN = 2; BLUE = 3; end methods (Access = private) % private so that you cant instantiate function out = Colors end end end
这不是一个真正的types,但是因为MATLAB是松散types的,所以如果你使用整数,你可以做一些近似的事情:
line1 = Colors.RED; ... if Colors.BLUE == line1 end
在这种情况下,MATLAB“枚举”接近C样式枚举 – replace整数的语法。
通过静态方法的仔细使用,你甚至可以让MATLAB的枚举方法Ada的复杂性,但不幸的是用笨拙的语法。
从R2010b开始,MATLAB支持枚举。
来自文档的示例:
classdef Colors properties R = 0; G = 0; B = 0; end methods function c = Colors(r, g, b) cR = r; cG = g; cB = b; end end enumeration Red (1, 0, 0) Green (0, 1, 0) Blue (0, 0, 1) end end
如果你想做一些与 Marcbuild议类似的东西,你可以简单地用一个结构来表示你的枚举types,而不是一个全新的类:
colors = struct('RED',1,'GREEN',2,'BLUE',3);
一个好处是你可以用两种不同的方式轻松访问结构。 您可以直接使用字段名称指定一个字段:
a = colors.RED;
或者如果string中包含字段名称,则可以使用dynamic字段名称 :
a = colors.('RED');
实际上,Marc做出的build议有一些好处,并且创build一个全新的类来表示一个“枚举”对象:
- 您可以控制对象的修改方式。
- 您可以将定义保存在一个地方,并在多个地方轻松使用。
- 您可以控制失败并使其更“优雅”,如果您尝试访问不存在的字段(而不是抛出错误),则返回空matrix。
但是,如果你不需要这种复杂性,只需要做一些快速的事情,结构就可能是最简单和最直接的实现。 它也将使用旧版本的MATLAB,不使用最新的OOP框架。
在MATLAB R2009b中实际上有一个名为“枚举”的关键字。 这似乎是无证的,我不能说我知道如何使用它,但function可能在那里。
你可以在matlabroot\toolbox\distcomp\examples\+examples
find它
classdef(Enumeration) DmatFileMode < int32 enumeration ReadMode(0) ReadCompatibilityMode(1) WriteMode(2) end <snip> end
你也可以使用Matlab代码中的Java枚举类。 用Java定义它们,并将它们放在Matlab的javaclasspath中。
// Java class definition package test; public enum ColorEnum { RED, GREEN, BLUE }
您可以通过M代码中的名称来引用它们。
mycolor = test.ColorEnum.RED if mycolor == test.ColorEnum.RED disp('got red'); else disp('got other color'); end % Use ordinal() to get a primitive you can use in a switch statement switch mycolor.ordinal case test.ColorEnum.BLUE.ordinal disp('blue'); otherwise disp(sprintf('other color: %s', char(mycolor.toString()))) end
不过,它不会与其他types进行比较。 和string比较有一个奇数返回大小。
>> test.ColorEnum.RED == 'GREEN' ans = 0 >> test.ColorEnum.RED == 'RED' ans = 1 1 1
你可以创build一个类似Java旧的types安全模式的Matlab类。 Marc的解决scheme的一个修改可以从C风格的types定义到更像Java风格的types安全枚举。 在这个版本中,常量中的值是键入的Color对象。
好处:
- 可以通过==和其他操作来检查types(在运行时),以防止与原始数字或其他types的枚举的意外比较。
- 您可以显式检查variables的types(在运行时)。
- 值以可读名称而不是不透明代码显示。
- 像平均()和std()这样的操作在枚举上是没有意义的操作是不允许的。
缺点:
- 更长的类定义。 但是,这是所有的样板,并可以重用任何其他枚举类,只改变类名和常量属性。
- 这些枚举不能直接在开关块中使用。 需要将代码popup,这样会失去一些types的安全性。
- 对象比基元要慢。 相关的,如果你在循环内使用常量。
总的来说,我不知道哪种方法更好。 在实践中没有用过。
classdef (Sealed) Color %COLOR Example of Java-style typesafe enum for Matlab properties (Constant) RED = Color(1, 'RED'); GREEN = Color(2, 'GREEN'); BLUE = Color(3, 'BLUE'); end properties (SetAccess=private) % All these properties are immutable. Code; Name; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% methods (Access = private) %private so that you can't instatiate directly function out = Color(InCode, InName) out.Code = InCode; out.Name = InName; end end methods (Static = true) function needa(obj) %NEEDA Asserts that obj must be a Color if ~isa(obj, mfilename) error('Input must be a %s; got a %s', mfilename, class(obj)); end end end methods (Access = public) function display(obj) disp([inputname(1) ' =']); disp(obj); end function disp(obj) if isscalar(obj) disp(sprintf('%s: %s (%d)', class(obj), obj.Name, obj.Code)); else disp(sprintf('%s array: size %s', class(obj), mat2str(size(obj)))); end end function out = eq(a, b) %EQ Basic "type-safe" eq check_type_safety(a, b); out = [a.Code] == [b.Code]; end function [tf,loc] = ismember(a, b) check_type_safety(a, b); [tf,loc] = ismember([a.Code], [b.Code]); end function check_type_safety(varargin) %CHECK_TYPE_SAFETY Check that all inputs are of this enum type for i = 1:nargin if ~isa(varargin{i}, mfilename) error('Non-typesafe comparison of %s vs. %s', mfilename, class(varargin{i})); end end end end end
这是一个运用它的function。
function do_stuff_with_color(c) %DO_STUFF_WITH_COLOR Demo use of the Color typesafe enum Color.needa(c); % Make sure input was a color if (c == Color.BLUE) disp('color was blue'); else disp('color was not blue'); end % To work with switch statements, you have to explicitly pop the code out switch c.Code case Color.BLUE.Code disp('blue'); otherwise disp(sprintf('some other color: %s', c.Name)); end
使用示例:
>> Color.RED == Color.RED ans = 1 >> Color.RED == 1 ??? Error using ==> Color>Color.check_type_safety at 55 Non-typesafe comparison of Color vs. double Error in ==> Color>Color.eq at 44 check_type_safety(a, b); >> do_stuff_with_color(Color.BLUE) color was blue blue >> do_stuff_with_color(Color.GREEN) color was not blue some other color: GREEN >> do_stuff_with_color(1+1) % oops - passing the wrong type, should error ??? Error using ==> Color>Color.needa at 26 Input must be a Color; got a double Error in ==> do_stuff_with_color at 4 Color.needa(c); % Make sure input was a color >>
在这两种方法中都有一个小小的偏差:把常数放在“==”左边以防止错误分配的C约定在这里没有太多帮助。 在Matlab中,如果在LHS上不小心使用了“=”这个常量,而不是错误,它只会创build一个名为Colors的本地结构variables,它将掩盖enum类。
>> Colors.BLUE = 42 Colors = BLUE: 42 >> Color.BLUE = 42 Color = BLUE: 42 >> Color.RED ??? Reference to non-existent field 'RED'.
在尝试了这个页面上的其他build议之后,我登陆了Andrew完全面向对象的方法。 非常好 – 谢谢Andrew。
然而,如果有人感兴趣的话,我(我认为是)做了一些改进。 特别是,我删除了需要双重指定枚举对象的名称。 现在使用reflection和元类系统来派生名称。 此外,重写了eq()和ismember()函数,以便为枚举对象的matrix返回适当形状的返回值。 最后,修改了check_type_safety()函数,使其与包目录(例如命名空间)兼容。
似乎很好地工作,但让我知道你的想法:
classdef (Sealed) Color %COLOR Example of Java-style typesafe enum for Matlab properties (Constant) RED = Color(1); GREEN = Color(2); BLUE = Color(3); end methods (Access = private) % private so that you can''t instatiate directly function out = Color(InCode) out.Code = InCode; end end % ============================================================================ % Everything from here down is completely boilerplate - no need to change anything. % ============================================================================ properties (SetAccess=private) % All these properties are immutable. Code; end properties (Dependent, SetAccess=private) Name; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% methods function out = eq(a, b) %EQ Basic "type-safe" eq check_type_safety(a, b); out = reshape([a.Code],size(a)) == reshape([b.Code],size(b)); end function [tf,loc] = ismember(a, b) check_type_safety(a, b); [tf,loc] = ismember(reshape([a.Code],size(a)), [b.Code]); end function check_type_safety(varargin) %CHECK_TYPE_SAFETY Check that all inputs are of this enum type theClass = class(varargin{1}); for ii = 2:nargin if ~isa(varargin{ii}, theClass) error('Non-typesafe comparison of %s vs. %s', theClass, class(varargin{ii})); end end end % Display stuff: function display(obj) disp([inputname(1) ' =']); disp(obj); end function disp(obj) if isscalar(obj) fprintf('%s: %s (%d)\n', class(obj), obj.Name, obj.Code); else fprintf('%s array: size %s\n', class(obj), mat2str(size(obj))); end end function name=get.Name(obj) mc=metaclass(obj); mp=mc.Properties; for ii=1:length(mp) if (mp{ii}.Constant && isequal(obj.(mp{ii}.Name).Code,obj.Code)) name = mp{ii}.Name; return; end; end; error('Unable to find a %s value of %d',class(obj),obj.Code); end; end end
谢谢梅森
如果您有权访问统计工具箱,则可以考虑使用分类对象 。
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'}; Toys{3} ans = 'Rex'
如果你只需要传递给C#或.NET程序集的枚举types,你可以用MATLAB 2010构造并传递枚举types:
A = NET.addAssembly(MyName.dll) % suppose you have enum called "MyAlerts" in your assembly myvar = MyName.MyAlerts.('value_1');
您也可以查看官方的MathWorks答案
如何在MATLAB 7.8(R2009a)中使用.NET枚举值?
// the enum "MyAlerts" in c# will look something like this public enum MyAlerts { value_1 = 0, value_2 = 1, MyAlerts_Count = 2, }