如何在MATLAB中创建枚举类型?

idd*_*ber 44 matlab enums matlab-class

MATLAB中是否有枚举类型?如果没有,有哪些替代方案?

Jon*_*nas 41

从R2010b开始,MATLAB支持枚举.

文档中的示例:

classdef Colors
   properties
      R = 0;
      G = 0;
      B = 0;
   end

   methods
      function c = Colors(r, g, b)
         c.R = r; c.G = g; c.B = b;
      end
   end

   enumeration
      Red   (1, 0, 0)
      Green (0, 1, 0)
      Blue  (0, 0, 1)
   end
end
Run Code Online (Sandbox Code Playgroud)

  • 对于未来的读者来说,这可能应该是公认的答案(尽管如此,所有好的解决方案) (6认同)
  • Url为更简单的例子@KronoS提到:[link](http://www.mathworks.de/de/help/matlab/matlab_oop/enumerations.html) (3认同)
  • 这是枚举类的一个更复杂的例子.在文档中可以找到更简单的一个. (2认同)

Mar*_*arc 26

您可以使用新式MATLAB类获得一些功能:

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
Run Code Online (Sandbox Code Playgroud)

这不是一个真正的类型,但由于MATLAB是松散类型的,如果你使用整数,你可以做一些近似它的事情:

line1 = Colors.RED;
...
if Colors.BLUE == line1
end
Run Code Online (Sandbox Code Playgroud)

在这种情况下,MATLAB"enums"接近C风格的枚举 - 替换整数的语法.

通过仔细使用静态方法,您甚至可以使MATLAB枚举方法在复杂性方面达到Ada,但不幸的是语法更加笨拙.

  • 实际上,对于简单的类,与使用大量全局结构相比,实际上没有时间损失.但是,良好实践的开发时间节省是巨大的,并且运行时很少会出现这样的问题.硬件便宜.编写软件的人不是. (5认同)

gno*_*ice 18

如果你想要做的事类似什么马克的建议,你可以简单地做一个结构来表示你的枚举类型,而不是一个全新的类:

colors = struct('RED', 1, 'GREEN', 2, 'BLUE', 3);
Run Code Online (Sandbox Code Playgroud)

一个好处是您可以通过两种不同的方式轻松访问结构.您可以使用字段名称直接指定字段:

a = colors.RED;
Run Code Online (Sandbox Code Playgroud)

或者,如果字符串中包含字段名称,则可以使用动态字段名称:

a = colors.('RED');
Run Code Online (Sandbox Code Playgroud)

事实上,做Marc建议并创建一个全新的类来表示"枚举"对象有一些好处:

  • 您可以控制对象的修改方式.
  • 您可以将定义保存在一个位置,并在多个位置轻松使用.
  • 您可以控制失败并使它们更"优雅",例如,如果您尝试访问不存在的字段(而不是抛出错误),则返回空矩阵.

但是,如果您不需要那种复杂性并且只需要快速执行某些操作,那么结构可能是最简单,最直接的实现.它也适用于不使用最新OOP框架的旧版MATLAB.


小智 8

MATLAB R2009b中实际上有一个名为'enumeration'的关键字.它似乎没有文档,我不能说我知道如何使用它,但功能可能就在那里.

你可以找到它 matlabroot\toolbox\distcomp\examples\+examples

classdef(Enumeration) DmatFileMode < int32

    enumeration
        ReadMode(0)
        ReadCompatibilityMode(1)
        WriteMode(2)
    end
<snip>
end
Run Code Online (Sandbox Code Playgroud)


And*_*nke 7

您还可以使用Matlab代码中的Java枚举类.用Java定义它们并将它们放在Matlab的javaclasspath中.

// Java class definition
package test;
public enum ColorEnum {
    RED, GREEN, BLUE
}
Run Code Online (Sandbox Code Playgroud)

您可以在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
Run Code Online (Sandbox Code Playgroud)

但是,它不会与其他类型进行比较.与string的比较具有奇数返回大小.

>> test.ColorEnum.RED == 'GREEN'
ans =
     0
>> test.ColorEnum.RED == 'RED'
ans =
     1     1     1
Run Code Online (Sandbox Code Playgroud)


And*_*nke 5

您可以创建一个类似Java旧的类型安全枚举模式的Matlab类.对Marc解决方案的修改可以将其从C风格的typedef转换为更像Java风格的类型安全枚举.在此版本中,常量中的值是类型化的Color对象.

好处:

  • 可以通过==和其他操作检查(在运行时)类型,以防止与原始数字或其他类型的枚举进行意外比较.
  • 您可以显式检查变量的类型(在运行时).
  • 值以可读名称而不是不透明代码显示.
  • 不允许在枚举上有意义的mean()和std()等操作.

缺点:

  • 更长的班级定义.但是,这是所有样板,并且可以重用于任何其他枚举类,只更改类名和常量属性.
  • 这些枚举不能直接在开关块中使用.需要弹出代码,这会失去一些类型的安全性.
  • 对象将比基元慢.如果你在循环中使用常量,则相关.

总的来说,我不知道哪种方法更好.在实践中没有使用过.

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
Run Code Online (Sandbox Code Playgroud)

这是一个锻炼它的功能.

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
Run Code Online (Sandbox Code Playgroud)

使用示例:

>> 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

>> 
Run Code Online (Sandbox Code Playgroud)

两种方法中的一个小怪癖:将常量放在"=="左侧以防止错误分配的C约定在这里没有多大帮助.在Matlab中,如果你不小心在LHS上使用"="这个常量而不是错误,它只会创建一个名为Colors的新的局部结构变量,它将掩盖枚举类.

>> Colors.BLUE = 42
Colors = 
    BLUE: 42
>> Color.BLUE = 42
Color = 
    BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
Run Code Online (Sandbox Code Playgroud)