Y a-t-il des types énumérés dans MATLAB? Sinon, quelles sont les alternatives?
Vous pouvez obtenir certaines fonctionnalités avec les classes MATLAB de nouveau style:
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
Ce n'est pas vraiment un type, mais comme MATLAB est mal typé, si vous utilisez des entiers, vous pouvez faire des choses qui se rapprochent de lui:
line1 = Colors.RED;
...
if Colors.BLUE == line1
end
Dans ce cas, les "énumérations" MATLAB sont proches des énumérations de style C - syntaxe de substitution pour les entiers.
Avec l'utilisation prudente de méthodes statiques, vous pouvez même faire en sorte que les énumérations MATLAB approchent Ada avec sophistication, mais malheureusement avec une syntaxe plus maladroite.
À partir de R2010b, MATLAB prend en charge les énumérations.
Exemple 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
Si vous voulez faire quelque chose similaire à ce que Marc a suggéré, vous pouvez simplement faire une structure pour représenter vos types énumérés au lieu d'une toute nouvelle classe:
colors = struct('RED', 1, 'GREEN', 2, 'BLUE', 3);
Un avantage est que vous pouvez facilement accéder aux structures de deux manières différentes. Vous pouvez spécifier un champ directement en utilisant le nom du champ:
a = colors.RED;
ou vous pouvez utiliser noms de champs dynamiques si vous avez le nom de champ dans une chaîne:
a = colors.('RED');
En vérité, il y a quelques avantages à faire ce que Marc a suggéré et à créer une toute nouvelle classe pour représenter un objet "enum":
Cependant, si vous n'avez pas besoin de ce type de complexité et que vous devez simplement faire quelque chose de rapide, une structure est probablement l'implémentation la plus simple et la plus simple. Il fonctionnera également avec les anciennes versions de MATLAB qui n'utilisent pas le plus récent framework OOP.
Il existe en fait un mot clé dans MATLAB R2009b appelé 'énumération'. Il semble ne pas être documenté, et je ne peux pas dire que je sais comment l'utiliser, mais la fonctionnalité est probablement là.
Vous pouvez le trouver dans matlabroot\toolbox\distcomp\examples\+examples
classdef(Enumeration) DmatFileMode < int32
enumeration
ReadMode(0)
ReadCompatibilityMode(1)
WriteMode(2)
end
<snip>
end
Vous pouvez également utiliser Java classes d'énumération à partir de votre code Matlab. Définissez-les dans Java et placez-les sur le javaclasspath de votre Matlab.
// Java class definition
package test;
public enum ColorEnum {
RED, GREEN, BLUE
}
Vous pouvez les référencer par leur nom dans le code 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
Cependant, il ne fera pas de comparaisons avec d'autres types. Et la comparaison avec la chaîne a une taille de retour étrange.
>> test.ColorEnum.RED == 'GREEN'
ans =
0
>> test.ColorEnum.RED == 'RED'
ans =
1 1 1
Vous pouvez créer une classe Matlab qui se comporte comme un ancien modèle d'énumération typesafe de Java . Une modification de solution de Marc pourrait le faire passer des typedefs de style C à des énumérations de typesafe de style Java. Dans cette version, les valeurs des constantes sont des objets Color de type.
Les avantages:
Inconvénients:
Dans l'ensemble, je ne sais pas quelle approche est la meilleure. N'ont pas non plus été utilisés dans la pratique.
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
Voici une fonction pour l'exercer.
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
Exemple d'utilisation:
>> 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
>>
Une bizarrerie mineure dans les deux approches: la convention C de mettre la constante à gauche du "==" pour éviter une mauvaise affectation n'aide pas autant ici. Dans Matlab, si vous utilisez accidentellement "=" avec cette constante sur le LHS, au lieu d'une erreur, cela créera simplement une nouvelle variable de structure locale nommée Colors et masquera la classe enum.
>> Colors.BLUE = 42
Colors =
BLUE: 42
>> Color.BLUE = 42
Color =
BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
Si vous avez accès à la boîte à outils des statistiques, vous pouvez envisager d'utiliser un objet catégorique .
Après avoir essayé les autres suggestions de cette page, j'ai atterri sur l'approche entièrement orientée objet d'Andrew. Très bien - merci Andrew.
Au cas où quelqu'un serait intéressé, cependant, j'ai apporté (ce que je pense) quelques améliorations. En particulier, j'ai supprimé la nécessité de double-spécifier le nom de l'objet enum. Les noms sont désormais dérivés à l'aide de la réflexion et du système de métaclasse. De plus, les fonctions eq () et ismember () ont été réécrites pour restituer des valeurs de retour correctement formées pour les matrices des objets enum. Et enfin, la fonction check_type_safety () a été modifiée pour la rendre compatible avec les répertoires de packages (par exemple les espaces de noms).
Semble bien fonctionner, mais faites-moi savoir ce que vous en pensez:
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
Merci Mason
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'};
Toys{3}
ans = 'Rex'
Si vous avez besoin des types énumérés juste pour passer à C # ou à l'assembly .NET, vous pouvez construire et passer les énumérations avec MATLAB 2010:
A = NET.addAssembly(MyName.dll)
% suppose you have enum called "MyAlerts" in your Assembly
myvar = MyName.MyAlerts.('value_1');
vous pouvez également consulter la réponse officielle de MathWorks à l'adresse
Comment utiliser les valeurs énumérées .NET dans 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,
}