2009-09-07 10 views

Respuesta

23

, usted puede obtener algunas de las funciones de MATLAB con las clases de nuevo estilo:

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 

esto no es realmente un tipo, pero desde MATLAB se escribe sin apretar, si utiliza números enteros, se pueden hacer cosas que aproximarla:

line1 = Colors.RED; 
... 
if Colors.BLUE == line1 
end 

En este caso, "enumeraciones" MATLAB están cerca de las enumeraciones de tipo C - sintaxis sustituto de números enteros.

Con el uso cuidadoso de métodos estáticos, incluso puede hacer que las enums de MATLAB se acerquen a la sofisticación de Ada, pero desafortunadamente con una sintaxis más torpe.

+0

acaba de ser conscientes de los posibles golpes de rendimiento cuando se utiliza el nuevo material orientado a objetos. En mi experiencia, introdujo una sobrecarga significativa. Sin embargo, realmente depende de lo que estés haciendo. –

+5

En realidad, para las clases simples, efectivamente no hay penalización de tiempo en comparación con el uso de muchas estructuras globales. Sin embargo, el ahorro de tiempo de desarrollo para buenas prácticas es sustancial, y raramente es el tiempo de ejecución como un problema. El hardware es barato. Las personas que escriben el software no lo son. – Marc

14

Si usted quiere hacer algo similares a lo Marc sugirió, podría simplemente hacer una structure para representar sus tipos enumerados en lugar de toda una clase nueva:

colors = struct('RED',1,'GREEN',2,'BLUE',3); 

Uno de los beneficios es que usted puede fácilmente acceder a las estructuras de dos maneras diferentes. Se puede especificar un campo directamente utilizando el nombre del campo:

a = colors.RED; 

o puede utilizar dynamic field names si tiene el nombre de campo en una cadena:

a = colors.('RED'); 

En verdad, hay algunas ventajas a hacer lo que sugirió Marc y crear una clase completamente nueva para representar un objeto "enumerado":

  • Puede controlar cómo se modifica el objeto.
  • Puede mantener la definición en un solo lugar y utilizarla fácilmente en varios lugares.
  • Puede controlar las fallas y hacerlas más "elegantes", como devolver una matriz vacía si intenta acceder a un campo inexistente (en lugar de arrojar un error).

Sin embargo, si no necesita ese tipo de complejidad y solo necesita hacer algo rápido, una estructura es probablemente la implementación más sencilla y directa. También funcionará con versiones anteriores de MATLAB que no usan el marco de OOP más nuevo.

5

Puede hacer una clase de Matlab que se comporte como Java's old typesafe enum pattern. Una modificación de Marc's solution podría llevarlo desde los typedefs de tipo C a más como enum de tipo de estilo Java. En esta versión, los valores en las constantes son objetos de Color tipeados.

El upsides:

  • El tipo se puede comprobar (en tiempo de ejecución) por == y otras operaciones para prevenir comparación accidental a valores numéricos primas o de otros tipos de enumeraciones.
  • Puede verificar explícitamente el tipo de sus variables (en tiempo de ejecución).
  • Los valores se muestran con nombres legibles en lugar de los códigos opacos.
  • Las operaciones como mean() y std() que no tienen sentido en las enumeraciones no están permitidas.

Desventajas:

  • más larga definición de clase. Pero, esto es todo repetitivo, y puede reutilizarse para cualquier otra clase enum, cambiando solo el nombre de la clase y las propiedades de Constante.
  • Estas enumeraciones no se pueden utilizar directamente en bloques de interruptores. Necesitas sacar el código, lo que pierde algún tipo de seguridad.
  • Los objetos serán más lentos que los primitivos. Pertinente si está usando constantes dentro de los bucles.

En general, no sé qué enfoque es mejor. No lo he usado en la práctica.

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 

Aquí hay una función para ejercitarlo.

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 

Ejemplo de uso:

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

>> 

Un capricho menor en ambos enfoques: la convención C de poner la constante en el lado izquierdo de la "==" para evitar la mala asignación no ayuda tanto aquí En Matlab, si accidentalmente usas "=" con esta constante en el LHS, en lugar de un error, creará una nueva variable de estructura local llamada Colors, y enmascarará la clase enum.

>> Colors.BLUE = 42 
Colors = 
    BLUE: 42 
>> Color.BLUE = 42 
Color = 
    BLUE: 42 
>> Color.RED 
??? Reference to non-existent field 'RED'. 
+0

Muy agradable, Andrew. Me preguntaba cuándo entraría. – Marc

7

También podría utilizar las clases enum de Java desde su código Matlab. Defínelos en Java y colóquelos en el javaclasspath de Matlab.

// Java class definition 
package test; 
public enum ColorEnum { 
    RED, GREEN, BLUE 
} 

Puede referenciarlos por nombre en código 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 

Sin embargo, no tomará comparaciones con otros tipos. Y la comparación con la cadena tiene un tamaño de retorno impar.

>> test.ColorEnum.RED == 'GREEN' 
ans = 
    0 
>> test.ColorEnum.RED == 'RED' 
ans = 
    1  1  1 
8

No es en realidad una palabra clave en MATLAB R2009b llama 'enumeración'. Parece que no está documentado, y no puedo decir que sé cómo usarlo, pero la funcionalidad probablemente esté allí.

Puede encontrarlo en matlabroot\toolbox\distcomp\examples\+examples

classdef(Enumeration) DmatFileMode < int32 

    enumeration 
     ReadMode(0) 
     ReadCompatibilityMode(1) 
     WriteMode(2) 
    end 
<snip> 
end 
+0

Esta es la forma correcta de hacerlo si va a realizar la generación de código. Se documenta mejor en la documentación de Simulink en "Definición de un tipo de datos enumerados". –

3

Después de probar las otras sugerencias en esta página, que aterrizó en el enfoque totalmente orientado a objetos de Andrew. Muy bien, gracias Andrew.

En caso de que alguien esté interesado, sin embargo, hice (lo que creo) algunas mejoras. En particular, eliminé la necesidad de especificar dos veces el nombre del objeto enum. Los nombres ahora se derivan usando la reflexión y el sistema de metaclase. Además, las funciones eq() y ismember() se volvieron a escribir para devolver valores de retorno con la forma adecuada para matrices de objetos enum. Y finalmente, la función check_type_safety() se modificó para hacerla compatible con los directorios de paquetes (por ejemplo, espacios de nombres).

parece funcionar muy bien, pero que me haga saber lo que piensa:

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 

Gracias, Mason

40

A partir de R2010b, MATLAB soporta enumeraciones.

Ejemplo de la documentation:

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

para lectores futuros, esta probablemente sea la respuesta aceptada (todas las soluciones son buenas) – Amro

+2

Este es un ejemplo más complicado de la clase enum. Se puede encontrar uno más simple dentro de la documentación. – KronoS

+3

Url para el ejemplo más simple @KronoS mencionado: [link] (http://www.mathworks.de/de/help/matlab/matlab_oop/enumerations.html) – JaBe

1

Si necesita los tipos enumerados sólo para pasar a C# o ensamblado de .NET, se puede construir y transmitir las enumeraciones con MATLAB 2010:

A = NET.addAssembly(MyName.dll) 
% suppose you have enum called "MyAlerts" in your assembly 
myvar = MyName.MyAlerts.('value_1'); 

también puede consultar la respuesta oficial de MathWorks al

How do I use .NET enumerated values in MATLAB 7.8 (R2009a)?

// the enum "MyAlerts" in c# will look something like this 
public enum MyAlerts 
{ 
    value_1 = 0, 
    value_2 = 1, 
    MyAlerts_Count = 2, 
} 
2
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'}; 

Toys{3} 
    ans = 'Rex' 
Cuestiones relacionadas