2009-09-07 22 views

risposta

23

è possibile ottenere alcune delle funzionalità con le classi MATLAB nuovo stile:

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 

questo non è davvero un tipo, ma dal momento che MATLAB è liberamente digitato, se si utilizza numeri interi, si possono fare cose che approssimarla:

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

In questo caso, MATLAB "enumerazioni" sono vicini a enumerazioni in stile C - sintassi sostituto per gli interi.

Con l'uso attento dei metodi statici, è possibile anche fare in modo che le enigmi di MATLAB si avvicinino alla complessità di Ada, ma sfortunatamente con una sintassi più impacciata.

+0

Basta essere consapevoli dei possibili colpi di prestazioni quando si utilizza il nuovo materiale orientato agli oggetti. Nella mia esperienza, ha introdotto un sovraccarico significativo. Dipende davvero da cosa stai facendo, comunque. –

+5

In realtà, per le classi semplici, non vi è effettivamente alcuna penalità di tempo rispetto all'utilizzo di molte strutture globali. Tuttavia, i risparmi in termini di tempo di sviluppo per le buone pratiche sono notevoli e raramente questo è un problema di runtime. L'hardware è economico. Le persone che scrivono il software non lo sono. – Marc

14

Se si vuole fare qualcosa di simile a quello che Marc suggerito, si potrebbe semplicemente fare una structure per rappresentare i vostri tipi enumerati, invece di un'intera classe nuova:

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

Un vantaggio è che si può facilmente accedere alle strutture in due modi diversi. È possibile specificare un campo direttamente utilizzando il nome del campo:

a = colors.RED; 

oppure è possibile utilizzare dynamic field names se avete il nome del campo in una stringa:

a = colors.('RED'); 

In realtà, ci sono alcuni vantaggi a fare cosa Marc ha suggerito e creando una classe completamente nuova per rappresentare un oggetto "enum":

  • È possibile controllare come l'oggetto viene modificato.
  • È possibile mantenere la definizione in un unico punto e utilizzarla facilmente in più posizioni.
  • È possibile controllare i guasti e renderli più "aggraziati", come restituire una matrice vuota se si tenta di accedere a un campo inesistente (al contrario di generare un errore).

Tuttavia, se non si ha bisogno di quel tipo di complessità e basta fare qualcosa in fretta, una struttura è probabilmente l'implementazione più semplice e diretta. Funzionerà anche con le versioni precedenti di MATLAB che non utilizzano il più recente framework OOP.

3

Se si ha accesso a Strumenti di statistica, è possibile prendere in considerazione l'utilizzo di categorical object.

5

È possibile creare una classe Matlab che si comporta come un Java's old typesafe enum pattern. Una modifica di Marc's solution potrebbe derivare da typedef in stile C a più simili enumerazioni in stile typesafe in stile Java. In questa versione, i valori nelle costanti sono digitati Oggetti colore.

I pregi:

  • Il tipo può essere controllata (in fase di esecuzione) di == e altre operazioni per evitare accidentali confronto al numerici elaborati o altri tipi di enumerazioni.
  • È possibile verificare esplicitamente il tipo di variabili (in fase di esecuzione).
  • I valori sono visualizzati con nomi leggibili anziché i codici opachi.
  • Operazioni come mean() e std() che non hanno senso sulle enumerazioni non sono consentite.

Svantaggi:

  • Longer definizione di classe. Ma questo è tutto il boilerplate e può essere riutilizzato per qualsiasi altra classe enum, cambiando solo il nome della classe e le proprietà Constant.
  • Queste enumerazioni non possono essere utilizzate direttamente nei blocchi di interruttori. È necessario far uscire il codice, che perde un po 'di sicurezza.
  • Gli oggetti saranno più lenti dei primitivi. Rilevante se si utilizzano le costanti all'interno dei loop.

Nel complesso, non so quale approccio sia migliore. Non ho usato neanche nella pratica.

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 

Ecco una funzione per esercitarlo.

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 

Esempio di utilizzo:

>> 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 cavillo minore in entrambi gli approcci: la convenzione C di mettere costante sulla mano sinistra del "==" per impedire cattiva assegnazione non aiuta tanto qui. In Matlab, se si utilizza accidentalmente "=" con questa costante sul LHS, invece di un errore, verrà semplicemente creata una nuova variabile di struttura locale denominata Colori e verrà mascherata la classe enum.

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

Molto carino, Andrew. Mi chiedevo quando avresti guadato. – Marc

7

È anche possibile utilizzare classi di enumerazione Java dal codice Matlab. Definiscili in Java e inseriscili nel javaclasspath di Matlab.

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

È possibile fare riferimento per nome in codice 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 

Tuttavia, non prenderà confronti con altri tipi. E il confronto con la stringa ha una dimensione di ritorno dispari.

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

V'è in realtà una parola chiave in MATLAB R2009b chiamato 'enumerazione'. Sembra non documentato, e non posso dire di sapere come usarlo, ma probabilmente c'è la funzionalità.

Lo si può trovare in matlabroot\toolbox\distcomp\examples\+examples

classdef(Enumeration) DmatFileMode < int32 

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

Questo è il modo corretto di farlo se si eseguirà la generazione del codice. È documentato meglio nella documentazione di Simulink in "Definizione di un tipo di dati enumerati". –

3

Dopo aver provato gli altri suggerimenti in questa pagina, sono atterrato su un approccio completamente orientato agli oggetti di Andrew. Molto carino - grazie Andrew.

Nel caso in cui qualcuno sia interessato, tuttavia, ho apportato alcuni miglioramenti (ciò che penso). In particolare, ho rimosso la necessità di specificare due volte il nome dell'oggetto enum. I nomi sono ora derivati ​​utilizzando il reflection e il sistema metaclass. Inoltre, le funzioni eq() e ismember() sono state riscritte per restituire valori di ritorno opportunamente sagomati per matrici di oggetti enum. Infine, la funzione check_type_safety() è stata modificata per renderla compatibile con le directory dei pacchetti (ad esempio namespace).

sembra funzionare bene, ma fatemi sapere cosa ne pensate:

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 

Grazie, Mason

40

A partire da R2010b, MATLAB supporta enumerazioni.

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

per i futuri lettori, questa probabilmente dovrebbe essere la risposta accettata (tutte le buone soluzioni comunque) – Amro

+2

Questo è un esempio più complicato della classe enum. È possibile trovare uno più semplice all'interno della documentazione. – KronoS

+3

Url per l'esempio più semplice @KronoS menzionato: [link] (http://www.mathworks.de/de/help/matlab/matlab_oop/enumerations.html) – JaBe

1

Se avete bisogno dei tipi enumerati solo per il passaggio a C# o assembly .NET, è possibile costruire e trasmettere le enumerazioni con MATLAB 2010:

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

puoi anche verificare la risposta ufficiale di 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'