Tipo enumerado - Enumerated type

En programación de computadoras , un tipo enumerado (también llamado enumeración , enum o factor en el lenguaje de programación R , y una variable categórica en estadísticas) es un tipo de datos que consta de un conjunto de valores con nombre llamados elementos , miembros , enumerador o enumeradores de el tipo. Los nombres de los enumeradores suelen ser identificadores que se comportan como constantes en el idioma. Un tipo enumerado puede verse como una unión etiquetada degenerada de tipo de unidad . Una variable que ha sido declarada como de tipo enumerado puede asignarse a cualquiera de los enumeradores como valor. En otras palabras, un tipo enumerado tiene valores que son diferentes entre sí, y que pueden ser comparados y asignados, pero el programador no especifica que tengan una representación concreta particular en la memoria de la computadora; los compiladores e intérpretes pueden representarlos arbitrariamente.

Por ejemplo, los cuatro palos en una baraja de cartas pueden ser cuatro enumeradores llamados Club , Diamante , Corazón y Espada , pertenecientes a un tipo enumerado llamado palo . Si se declara que una variable V tiene traje como tipo de datos, se le puede asignar cualquiera de esos cuatro valores.

Aunque los enumeradores suelen ser distintos, algunos idiomas pueden permitir que el mismo enumerador se incluya dos veces en la declaración del tipo. Los nombres de los enumeradores no necesitan ser semánticamente completos ni compatibles en ningún sentido. Por ejemplo, un tipo enumerado llamado color se puede definir para que consta de los enumeradores Rojo , Verde , Cebra , Falta y Tocino . En algunos idiomas, la declaración de un tipo enumerado también define intencionalmente un orden de sus miembros; en otros, los enumeradores están desordenados; en otros aún, un ordenamiento implícito surge del compilador que representa concretamente a los enumeradores como números enteros.

Algunos tipos de enumeradores pueden estar integrados en el lenguaje. El tipo booleano , por ejemplo, suele ser una enumeración predefinida de los valores False y True . Muchos idiomas permiten a los usuarios definir nuevos tipos enumerados.

Los valores y variables de un tipo enumerado generalmente se implementan como cadenas de bits de longitud fija , a menudo en un formato y tamaño compatibles con algún tipo de entero . Algunos lenguajes, especialmente los lenguajes de programación del sistema , permiten al usuario especificar la combinación de bits que se utilizará para cada enumerador. En la teoría de tipos, los tipos enumerados a menudo se consideran uniones etiquetadas de tipos de unidades . Dado que estos tipos son de forma , también pueden escribirse como números naturales.

Razón fundamental

Algunos lenguajes de programación tempranos no tenían originalmente tipos enumerados. Si un programador quisiera que una variable, por ejemplo myColor , tuviera un valor de rojo, la variable rojo se declararía y se le asignaría algún valor arbitrario, generalmente una constante entera. Luego, la variable roja se asignaría a myColor . Otras técnicas asignaron valores arbitrarios a cadenas que contenían los nombres de los enumeradores.

Estos valores arbitrarios a veces se denominan números mágicos, ya que a menudo no se explica cómo se obtuvieron los números o si sus valores reales eran significativos. Estos números mágicos podrían hacer que el código fuente sea más difícil de entender y mantener para otros.

Los tipos enumerados, por otro lado, hacen que el código sea más autodocumentado. Dependiendo del idioma, el compilador podría asignar automáticamente valores predeterminados a los enumeradores, ocultando así detalles innecesarios al programador. Es posible que estos valores ni siquiera sean visibles para el programador (ver información oculta ). Los tipos enumerados también pueden evitar que un programador escriba código ilógico, como realizar operaciones matemáticas en los valores de los enumeradores. Si se imprimiera el valor de una variable a la que se le asignó un enumerador, algunos lenguajes de programación también podrían imprimir el nombre del enumerador en lugar de su valor numérico subyacente. Una ventaja adicional es que los tipos enumerados pueden permitir a los compiladores imponer la corrección semántica. Por ejemplo: myColor = TRIANGLE puede estar prohibido, mientras myColor = RED se acepta, incluso si TRIÁNGULO y ROJO están representados internamente como 1 .

Conceptualmente, un tipo enumerado es similar a una lista de nominales (códigos numéricos), ya que a cada valor posible del tipo se le asigna un número natural distintivo. Un tipo enumerado dado es, por tanto, una implementación concreta de esta noción. Cuando el orden es significativo y / o se usa para la comparación, entonces un tipo enumerado se convierte en un tipo ordinal .

Convenciones

Los lenguajes de programación tienden a tener sus propios, a menudo múltiples, estilos de programación y convenciones de nomenclatura . La variable asignada a una enumeración suele ser un sustantivo en forma singular y, con frecuencia, sigue una convención de PascalCase o de mayúsculas , mientras que las minúsculas y otras se ven con menos frecuencia.

Sintaxis en varios lenguajes de programación

Pascal y lenguajes sintácticamente similares

Pascal

En Pascal , un tipo enumerado se puede declarar implícitamente enumerando los valores en una lista entre paréntesis:

  var
    suit: (clubs, diamonds, hearts, spades);

La declaración a menudo aparecerá en una declaración de sinónimo de tipo, de modo que se pueda usar para múltiples variables:

  type
    cardsuit = (clubs, diamonds, hearts, spades);
    card = record
             suit: cardsuit;
             value: 1 .. 13;
           end;
  var
    hand: array [ 1 .. 13 ] of card;
    trump: cardsuit;

El orden en el que se dan los valores de enumeración es importante. Un tipo enumerado es un tipo ordinal, y las predy succfunciones dará el valor previo o el siguiente de la enumeración, y ordpuede convertir los valores de enumeración a su representación número entero. Sin embargo, Standard Pascal no ofrece una conversión de tipos aritméticos a enumeraciones. Extended Pascal ofrece esta funcionalidad a través de una succfunción extendida . Algunos otros dialectos de Pascal lo permiten a través de conversiones de tipos. Algunos descendientes modernos de Pascal, como Modula-3 , proporcionan una sintaxis de conversión especial utilizando un método llamado VAL; Modula-3 también trata BOOLEANy CHARcomo tipos y usos enumerados predefinidos especiales ORDy VALpara la decodificación y codificación ASCII estándar .

Los lenguajes de estilo Pascal también permiten que la enumeración se use como índice de matriz:

  var
    suitcount: array [cardsuit] of integer;

Ada

En Ada , el uso de "=" fue reemplazado por "es" dejando la definición bastante similar:

type Cardsuit is (clubs, diamonds, hearts, spades);

Además de Pred, Succ, Valy PosAda también soporta la conversión de series simples a través de Imagey Value.

Similar a los lenguajes de estilo C, Ada permite especificar la representación interna de la enumeración:

for Cardsuit use
  (clubs => 1, diamonds => 2, hearts => 4, spades => 8);

A diferencia de los lenguajes de estilo C, Ada también permite especificar el número de bits de la enumeración:

for Cardsuit'Size use 4;  -- 4 bits

Además, se pueden usar enumeraciones como índices para matrices, como en Pascal, pero hay atributos definidos para enumeraciones

   Shuffle : constant array(Cardsuit) of Cardsuit :=
     (Clubs => Cardsuit'Succ(Clubs), -- see attributes of enumerations 'First, 'Last, 'Succ, 'Pred
      Diamonds => Hearts, --an explicit value
      Hearts => Cardsuit'Last, --first enumeration value of type Cardsuit e.g., clubs
      Spades => Cardsuit'First --last enumeration value of type Cardsuit e.g., spades
      );

Como Modula-3 Ada trata Booleany Charactercomo Standardtipos especiales predefinidos (en el paquete " ") enumerados. A diferencia de Modula-3, también se pueden definir tipos de caracteres propios:

type Cards is ('7', '8', '9', 'J', 'Q', 'K', 'A');

C y lenguajes sintácticamente similares

C

El dialecto K&R original del lenguaje de programación C no tenía tipos enumerados. En C, las enumeraciones se crean mediante definiciones explícitas (la enumpalabra clave por sí misma no causa la asignación de almacenamiento) que usan la enumpalabra clave y recuerdan las definiciones de estructura y unión :

enum cardsuit {
    Clubs,
    Diamonds,
    Hearts,
    Spades
};

struct card {
    enum cardsuit suit;
    short int value;
} hand[13];

enum cardsuit trump;

C expone la representación entera de los valores de enumeración directamente al programador. Los valores enteros y de enumeración se pueden mezclar libremente y se permiten todas las operaciones aritméticas en valores de enumeración. Incluso es posible que una variable de enumeración contenga un número entero que no represente ninguno de los valores de enumeración. De hecho, de acuerdo con la definición del lenguaje, el código anterior definirá Clubs, Diamonds, Hearts, y Spadescomo constantes de tipo int, que sólo se transformarán (silencio) para enum cardsuitsi están almacenados en una variable de ese tipo.

C también permite al programador elegir los valores de las constantes de enumeración explícitamente, incluso sin tipo. Por ejemplo,

enum cardsuit {
    Clubs    = 1,
    Diamonds = 2,
    Hearts   = 4,
    Spades   = 8
};

podría usarse para definir un tipo que permita representar conjuntos matemáticos de trajes como enum cardsuitoperaciones lógicas bit a bit.

C#

Los tipos enumerados en el lenguaje de programación C # conservan la mayor parte de la semántica de "entero pequeño" de las enumeraciones de C. Algunas operaciones aritméticas no están definidas para enumeraciones, pero un valor de enumeración se puede convertir explícitamente en un número entero y viceversa, y una variable de enumeración puede tener valores que no fueron declarados por la definición de enumeración. Por ejemplo, dado

enum Cardsuit
{
    Clubs,
    Diamonds,
    Spades,
    Hearts
}

las expresiones CardSuit.Diamonds + 1y CardSuit.Hearts - CardSuit.Clubsse permiten directamente (porque puede tener sentido recorrer la secuencia de valores o preguntar cuántos pasos hay entre dos valores), pero CardSuit.Hearts * CardSuit.Spadesse considera que tiene menos sentido y solo se permite si los valores se convierten primero en números enteros .

C # también proporciona la característica similar a C de poder definir valores enteros específicos para enumeraciones. Al hacer esto, es posible realizar operaciones binarias en enumeraciones, tratando así los valores de enumeración como conjuntos de banderas. Estos indicadores se pueden probar mediante operaciones binarias o con el método incorporado 'HasFlag' del tipo Enum.

La definición de enumeración define nombres para los valores enteros seleccionados y es azúcar sintáctica , ya que es posible asignar a una variable de enumeración otros valores enteros que no están en el alcance de la definición de enumeración.

C ++

C ++ tiene tipos de enumeración que se heredan directamente de C y funcionan principalmente como estos, excepto que una enumeración es un tipo real en C ++, lo que brinda una verificación adicional en tiempo de compilación. Además (como con las estructuras), la enumpalabra clave C ++ se combina automáticamente con typedef , de modo que en lugar de nombrar el tipo enum name, simplemente nombrarlo name. Esto se puede simular en C usando un typedef:typedef enum {Value1, Value2} name;

C ++ 11 proporciona un segundo tipo de enumeración con seguridad de tipos que no se convierte implícitamente en un tipo entero. Permite definir la transmisión io para ese tipo. Además, las enumeraciones no se filtran, por lo que deben usarse con Enumeration Type::enumeration. Esto se especifica mediante la frase "clase enum". Por ejemplo:

enum class Color {Red, Green, Blue};

El tipo subyacente es un tipo integral definido por la implementación que es lo suficientemente grande como para contener todos los valores enumerados (¡no tiene que ser el tipo más pequeño posible!). En C ++ puede especificar el tipo subyacente directamente. Eso permite "declaraciones hacia adelante" de enumeraciones:

enum class Color : long {Red, Green, Blue};  // must fit in size and memory layout the type 'long'
enum class Shapes : char;  // forward declaration. If later there are values defined that don't fit in 'char' it is an error.

Ir

Go usa la iotapalabra clave para crear constantes enumeradas.

type ByteSize float64

const (
    _           = iota // ignore first value by assigning to blank identifier
    KB ByteSize = 1 << (10 * iota)
    MB
    GB
)

Java

La versión 5.0 de J2SE del lenguaje de programación Java agregó tipos enumerados cuya sintaxis de declaración es similar a la de C :

enum Cardsuit { CLUBS, DIAMONDS, SPADES, HEARTS };
...
Cardsuit trump;

Sin embargo, el sistema de tipos de Java trata las enumeraciones como un tipo separado de los enteros y no se permite la mezcla de valores de enumeración y enteros. De hecho, un tipo de enumeración en Java es en realidad una clase especial generada por el compilador en lugar de un tipo aritmético, y los valores de enumeración se comportan como instancias globales pregeneradas de esa clase. Los tipos de enumeración pueden tener métodos de instancia y un constructor (cuyos argumentos se pueden especificar por separado para cada valor de enumeración). Todos los tipos de enumeración extienden implícitamente la Enumclase abstracta. No se puede crear una instancia de un tipo de enumeración directamente.

Internamente, cada valor de enumeración contiene un número entero, correspondiente al orden en el que se declaran en el código fuente, comenzando desde 0. El programador no puede establecer un entero personalizado para un valor de enumeración directamente, pero se pueden definir constructores sobrecargados que luego pueden asignar valores arbitrarios a miembros autodefinidos de la clase enum. La definición de captadores permite el acceso a esos miembros autodefinidos. El número entero interno se puede obtener a partir de un valor de enumeración mediante el ordinal()método, y la lista de valores de enumeración de un tipo de enumeración se puede obtener en orden mediante el values()método. Por lo general, se desaconseja que los programadores conviertan las enumeraciones en números enteros y viceversa. Los tipos enumerados son Comparable, utilizando el entero interno; como resultado, se pueden ordenar.

La biblioteca estándar de Java proporciona clases de utilidad para usar con enumeraciones. La EnumSetclase implementa una serie Setde valores de enumeración; se implementa como una matriz de bits , lo que lo hace muy compacto y tan eficiente como la manipulación explícita de bits, pero más seguro. La EnumMapclase implementa una serie Mapde valores de enumeración al objeto. Se implementa como una matriz, con el valor entero del valor de enumeración que actúa como índice.

Perl

Los lenguajes tipados dinámicamente en la tradición sintáctica de C (por ejemplo, Perl o JavaScript ) no proporcionan, en general, enumeraciones. Pero en la programación de Perl se puede obtener el mismo resultado con la lista de cadenas abreviadas y hashes (posiblemente cortes ):

my @enum = qw(Clubs Diamonds Hearts Spades);
my( %set1, %set2 );
@set1{@enum} = ();          # all cleared
@set2{@enum} = (1) x @enum; # all set to 1
$set1{Clubs} ...            # false
$set2{Diamonds} ...         # true

Raku

Raku (anteriormente conocido como Perl 6) admite enumeraciones. Hay varias formas de declarar enumeraciones en Raku, todas creando un mapa de back-end.

enum Cat <sphynx siamese bengal shorthair other>; # Using "quote-words"
enum Cat ('sphynx', 'siamese', 'bengal', 'shorthair', 'other'); # Using a list
enum Cat (sphynx => 0, siamese => 1, bengal => 2, shorthair => 3, other => 4); # Using Pair constructors
enum Cat (:sphynx(0), :siamese(1), :bengal(2), shorthair(3), :other(4)); # Another way of using Pairs, you can also use `:0sphynx`

PHP

Se agregaron enumeraciones en PHP versión 8.1.

enum CardSuit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

Oxido

Aunque Rust usa la enumpalabra clave como C, la usa para describir uniones etiquetadas , cuyas enumeraciones pueden considerarse una forma degenerada de. Por lo tanto, las enumeraciones de Rust son mucho más flexibles y pueden contener variantes de estructura y tupla.

enum Message {
    Quit,
    Move { x: i32, y: i32 }, // struct
    Write(String), // single-element tuple
    ChangeColor(i32, i32, i32), // three-element tuple
}

Rápido

En C, las enumeraciones asignan nombres relacionados a un conjunto de valores enteros. En Swift , las enumeraciones son mucho más flexibles y no necesitan proporcionar un valor para cada caso de enumeración. Si se proporciona un valor (denominado valor bruto ) para cada caso de enumeración, el valor puede ser una cadena, un carácter o un valor de cualquier tipo entero o de punto flotante.

Alternativamente, los casos de enumeración pueden especificar valores asociados de cualquier tipo para ser almacenados junto con cada valor de caso diferente, al igual que lo hacen las uniones o variantes en otros idiomas. Se puede definir un conjunto común de casos relacionados como parte de una enumeración, cada uno de los cuales tiene asociado un conjunto diferente de valores de tipos apropiados.

En Swift, las enumeraciones son un tipo de primera clase. Adoptan muchas características que tradicionalmente solo son compatibles con las clases, como propiedades calculadas para proporcionar información adicional sobre el valor actual de la enumeración y métodos de instancia para proporcionar funcionalidad relacionada con los valores que representa la enumeración. Las enumeraciones también pueden definir inicializadores para proporcionar un valor de caso inicial y pueden extenderse para expandir su funcionalidad más allá de su implementación original; y puede ajustarse a los protocolos para proporcionar una funcionalidad estándar.

enum CardSuit {
    case clubs
    case diamonds
    case hearts
    case spades
}

A diferencia de C y Objective-C , a los casos de enumeración Swift no se les asigna un valor entero predeterminado cuando se crean. En el ejemplo de CardSuit anterior, tréboles, diamantes, corazones y espadas no equivalen implícitamente a 0, 1, 2 y 3. En cambio, los diferentes casos de enumeración son valores completos por derecho propio, con un tipo de CardSuit definido explícitamente .

Pueden aparecer varios casos en una sola línea, separados por comas:

enum CardSuit {
    case clubs, diamonds, hearts, spades
}

Cuando se trabaja con enumeraciones que almacenan valores sin procesar enteros o de cadena, no es necesario asignar explícitamente un valor sin procesar para cada caso porque Swift asignará automáticamente los valores.

Por ejemplo, cuando se utilizan números enteros para valores brutos, el valor implícito para cada caso es uno más que en el caso anterior. Si el primer caso no tiene un valor establecido, su valor es 0.

La siguiente enumeración es un refinamiento de la enumeración de planetas anterior, con valores enteros sin procesar para representar el orden de cada planeta desde el sol:

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

En el ejemplo anterior, Planet.mercury tiene un valor bruto explícito de 1, Planet.venus tiene un valor bruto implícito de 2, y así sucesivamente.

"Los detalles se encuentran en la documentación de Swift en línea aquí".

Mecanografiado

TypeScript agrega un tipo de datos 'enum' a JavaScript.

enum Cardsuit {Clubs, Diamonds, Hearts, Spades};
var c: Cardsuit = Cardsuit.Diamonds;

De forma predeterminada, las enumeraciones numeran a los miembros a partir de 0; esto se puede anular estableciendo el valor del primero:

enum Cardsuit {Clubs = 1, Diamonds, Hearts, Spades};
var c: Cardsuit = Cardsuit.Diamonds;

Todos los valores se pueden configurar:

enum Cardsuit {Clubs = 1, Diamonds = 2, Hearts = 4, Spades = 8};
var c: Cardsuit = Cardsuit.Diamonds;

TypeScript admite la asignación del valor numérico a su nombre. Por ejemplo, esto busca el nombre del valor 2:

enum Cardsuit {Clubs = 1, Diamonds, Hearts, Spades};
var suitName: string = Cardsuit[2];

alert(suitName);

Pitón

Se enumagregó un módulo a la biblioteca estándar de Python en la versión 3.4.

from enum import Enum
class Cards(Enum):
    CLUBS = 1
    DIAMONDS = 2
    HEARTS = 3
    SPADES = 4

También hay una API funcional para crear enumeraciones con índices generados automáticamente (comenzando con uno):

Cards = Enum('Cards', 'CLUBS DIAMONDS HEARTS SPADES'])

Las enumeraciones de Python no imponen la corrección semántica (una comparación sin sentido con una enumeración incompatible siempre devuelve False en lugar de generar un TypeError ):

>>> Color = Enum("Color", "RED GREEN BLUE")
>>> Shape = Enum("Shape", ["CIRCLE", "TRIANGLE", "SQUARE", "HEXAGON"])
>>> def has_vertices(shape):
... 	return shape != Shape.CIRCLE
...
>>> has_vertices(Color.GREEN)
True

Fortran

Fortran solo ha enumerado tipos para la interoperabilidad con C; por lo tanto, la semántica es similar a C y, como en C, los valores de enumeración son solo números enteros y no se realiza ninguna verificación de tipo adicional. El ejemplo de C de arriba se puede escribir en Fortran como

enum, bind( C )
  enumerator :: CLUBS = 1, DIAMONDS = 2, HEARTS = 4, SPADES = 8
end enum

Visual Basic / VBA

A los tipos de datos enumerados en Visual Basic (hasta la versión 6) y VBA se les asigna automáticamente el " Long" tipo de datos y también se convierten en un tipo de datos por sí mismos:

'Zero-based
Enum CardSuit
    Clubs
    Diamonds
    Hearts
    Spades
End Enum

Sub EnumExample()
    Dim suit As CardSuit
    suit = Diamonds
    MsgBox suit
End Sub

Código de ejemplo en VB.NET

Enum CardSuit
    Clubs
    Diamonds
    Hearts
    Spades
End Enum

Sub EnumExample()
    Dim suit As CardSuit
    suit = CardSuit.Diamonds
    MessageBox.show(suit)
End Sub

Ceceo

Common Lisp usa el especificador de tipo de miembro, por ejemplo,

(deftype cardsuit ()
  '(member club diamond heart spade))

que establece que el objeto es de tipo palo de naipes si es #'eqltrébol, diamante, corazón o espada. Sin embargo, el especificador de tipo de miembro no es válido como un especialista en parámetros de Common Lisp Object System (CLOS). En su lugar, (eql atom)se (member atom)puede usar , que es el equivalente a (es decir, solo se puede especificar un miembro del conjunto con un especificador de tipo eql, sin embargo, se puede usar como un especializador de parámetros CLOS). En otras palabras, para definir métodos para cubrir un tipo enumerado, se debe definir un método para cada elemento específico de ese tipo.

Adicionalmente,

(deftype finite-element-set-type (&rest elements)
   `(member ,@elements))

se puede utilizar para definir tipos enumerados arbitrarios en tiempo de ejecución. Por ejemplo

(finite-element-set-type club diamond heart spade)

se referiría a un tipo equivalente a la definición anterior de carduit, ya que, por supuesto, simplemente habría estado usando

(member club diamond heart spade)

pero puede ser menos confuso con la función #'memberpor razones estilísticas.

Tipo de datos algebraicos en programación funcional

En lenguajes de programación funcional en el linaje ML (por ejemplo, ML estándar (SML), OCaml y Haskell ), se puede usar un tipo de datos algebraicos con solo constructores nulares para implementar un tipo enumerado. Por ejemplo (en la sintaxis de las firmas SML):

datatype cardsuit = Clubs | Diamonds | Hearts | Spades
type card = { suit: cardsuit; value: int }
val hand : card list
val trump : cardsuit

En estos lenguajes, la representación de números enteros pequeños está completamente oculta al programador, si es que la implementación emplea tal representación. Sin embargo, Haskell tiene la Enum clase de tipo que un tipo puede derivar o implementar para obtener un mapeo entre el tipo y Int.

Bases de datos

Algunas bases de datos admiten tipos enumerados directamente. MySQL proporciona un tipo enumerado ENUMcon valores permitidos especificados como cadenas cuando se crea una tabla. Los valores se almacenan como índices numéricos con la cadena vacía almacenada como 0, el primer valor de cadena almacenado como 1, el segundo valor de cadena almacenado como 2, etc. Los valores se pueden almacenar y recuperar como índices numéricos o valores de cadena.

Ejemplo:

CREATE TABLE shirts (
    name VARCHAR(40),
    size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);

Esquema XML

El esquema XML admite tipos enumerados a través de la faceta de enumeración utilizada para restringir la mayoría de los tipos de datos primitivos, como las cadenas.

<xs:element name="cardsuit">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="Clubs"/>
      <xs:enumeration value="Diamonds"/>
      <xs:enumeration value="Hearts"/>
      <xs:enumeration value="Spades"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

Ver también

Referencias

enlaces externos