Tipo enumerado - Enumerated type

Em programação de computador , um tipo enumerado (também chamado de enumeração , enum ou fator na linguagem de programação R e uma variável categórica em estatísticas) é um tipo de dados que consiste em um conjunto de valores nomeados chamados de elementos , membros , enumeral ou enumeradores de o tipo. Os nomes dos enumeradores são geralmente identificadores que se comportam como constantes na linguagem. Um tipo enumerado pode ser visto como uma união marcada degenerada do tipo de unidade . Uma variável que foi declarada como tendo um tipo enumerado pode ser atribuída a qualquer um dos enumeradores como um valor. Em outras palavras, um tipo enumerado tem valores que são diferentes uns dos outros e que podem ser comparados e atribuídos, mas não são especificados pelo programador como tendo qualquer representação concreta particular na memória do computador; compiladores e interpretadores podem representá-los arbitrariamente.

Por exemplo, os quatro naipes em um baralho de cartas podem ser quatro enumeradores chamados Clube , Diamante , Coração e Espada , pertencentes a um tipo enumerado chamado naipe . Se uma variável V é declarada tendo suit como seu tipo de dados, pode-se atribuir qualquer um desses quatro valores a ela.

Embora os enumeradores sejam geralmente distintos, algumas linguagens podem permitir que o mesmo enumerador seja listado duas vezes na declaração do tipo. Os nomes dos enumeradores não precisam ser semanticamente completos ou compatíveis em nenhum sentido. Por exemplo, um tipo enumerado chamado cor pode ser definido para consistir nos enumeradores Red , Green , Zebra , Missing e Bacon . Em algumas linguagens, a declaração de um tipo enumerado também define intencionalmente uma ordem de seus membros; em outros, os enumeradores são desordenados; em outros ainda, uma ordenação implícita surge do compilador que representa concretamente os enumeradores como inteiros.

Alguns tipos de enumerador podem ser integrados à linguagem. O tipo booleano , por exemplo, costuma ser uma enumeração predefinida dos valores False e True . Muitos idiomas permitem que os usuários definam novos tipos enumerados.

Valores e variáveis ​​de um tipo enumerado são geralmente implementados como cadeias de bits de comprimento fixo , geralmente em um formato e tamanho compatível com algum tipo de número inteiro . Algumas linguagens, especialmente as linguagens de programação do sistema , permitem que o usuário especifique a combinação de bits a ser usada para cada enumerador. Na teoria dos tipos, os tipos enumerados são freqüentemente considerados como uniões marcadas de tipos de unidade . Como esses tipos têm forma , eles também podem ser escritos como números naturais.

Justificativa

Algumas das primeiras linguagens de programação não tinham originalmente tipos enumerados. Se um programador quisesse que uma variável, por exemplo myColor , tivesse o valor vermelho, a variável red seria declarada e atribuída a algum valor arbitrário, geralmente uma constante inteira. A variável red seria então atribuída a myColor . Outras técnicas atribuíram valores arbitrários a strings contendo os nomes dos enumeradores.

Esses valores arbitrários às vezes eram chamados de números mágicos, pois muitas vezes não havia explicação de como os números foram obtidos ou se seus valores reais eram significativos. Esses números mágicos podem tornar o código-fonte mais difícil para outras pessoas entenderem e manterem.

Os tipos enumerados, por outro lado, tornam o código mais autodocumentado. Dependendo da linguagem, o compilador pode atribuir automaticamente valores padrão aos enumeradores, ocultando assim detalhes desnecessários do programador. Esses valores podem nem ser visíveis para o programador (veja ocultação de informações ). Os tipos enumerados também podem impedir que um programador escreva código ilógico, como realizar operações matemáticas nos valores dos enumeradores. Se o valor de uma variável atribuída a um enumerador fosse impresso, algumas linguagens de programação também poderiam imprimir o nome do enumerador em vez de seu valor numérico subjacente. Uma outra vantagem é que os tipos enumerados podem permitir que os compiladores reforcem a correção semântica. Por exemplo: myColor = TRIANGLE pode ser proibido, embora myColor = RED seja aceito, mesmo que TRIÂNGULO e VERMELHO sejam ambos internamente representados como 1 .

Conceitualmente, um tipo enumerado é semelhante a uma lista de nominais (códigos numéricos), uma vez que a cada valor possível do tipo é atribuído um número natural distinto. Um determinado tipo enumerado é, portanto, uma implementação concreta dessa noção. Quando a ordem é significativa e / ou usada para comparação, um tipo enumerado se torna um tipo ordinal .

Convenções

Linguagens de programação tendem a ter seus próprios, muitas vezes múltiplos, estilos de programação e convenções de nomenclatura . A variável atribuída a uma enumeração é geralmente um substantivo no singular e frequentemente segue uma convenção PascalCase ou maiúscula , enquanto minúsculas e outras são vistas com menos frequência.

Sintaxe em várias linguagens de programação

Pascal e linguagens sintaticamente semelhantes

Pascal

Em Pascal , um tipo enumerado pode ser declarado implicitamente listando os valores em uma lista entre parênteses:

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

A declaração geralmente aparecerá em uma declaração de sinônimo de tipo, de modo que possa ser usada para várias variáveis:

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

A ordem em que os valores de enumeração são fornecidos é importante. Um tipo enumerado é um tipo ordinal e as funções prede succfornecerão o valor anterior ou seguinte da enumeração e ordpodem converter os valores de enumeração em sua representação inteira. No entanto, o Pascal padrão não oferece uma conversão de tipos aritméticos para enumerações. Pascal estendido oferece essa funcionalidade por meio de uma succfunção estendida . Alguns outros dialetos Pascal permitem isso por meio de conversão de tipos. Alguns descendentes modernos de Pascal, como Modula-3 , fornecem uma sintaxe de conversão especial usando um método chamado VAL; Modula-3 também trata BOOLEANe CHARcomo tipos e usos enumerados predefinidos especiais ORDe VALpara decodificação e codificação ASCII padrão .

As linguagens de estilo Pascal também permitem que a enumeração seja usada como índice de matriz:

  var
    suitcount: array [cardsuit] of integer;

Ada

Em Ada , o uso de "=" foi substituído por "é", deixando a definição bastante semelhante:

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

Além de Pred, Succ, Vale PosAda também suporta conversões de cadeia simples através do Imagee Value.

Semelhante às linguagens de estilo C, Ada permite que a representação interna da enumeração seja especificada:

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

Ao contrário das linguagens de estilo C, Ada também permite que o número de bits da enumeração seja especificado:

for Cardsuit'Size use 4;  -- 4 bits

Além disso, pode-se usar enumerações como índices para matrizes, como em Pascal, mas existem atributos definidos para enumerações

   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 Booleane Charactercomo Standardtipos enumerados especiais pré-definidos (no pacote " "). Ao contrário do Modula-3, também é possível definir os próprios tipos de caracteres:

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

Linguagens C e sintaticamente semelhantes

C

O dialeto K&R original da linguagem de programação C não tinha tipos enumerados. Em C, as enumerações são criadas por definições explícitas (a enumpalavra - chave por si só não causa alocação de armazenamento) que usam a enumpalavra - chave e são uma reminiscência de definições de estrutura e união :

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

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

enum cardsuit trump;

C expõe a representação inteira dos valores de enumeração diretamente para o programador. Inteiros e valores enum podem ser misturados livremente, e todas as operações aritméticas em valores enum são permitidas. É até possível que uma variável enum contenha um inteiro que não represente nenhum dos valores de enumeração. Na verdade, de acordo com a definição de linguagem, o código de cima vai definir Clubs, Diamonds, Hearts, e Spadescomo constantes de tipo int, os quais só serão convertidos (silenciosamente) para enum cardsuitse eles são armazenados numa variável desse tipo.

C também permite que o programador escolha os valores das constantes de enumeração explicitamente, mesmo sem tipo. Por exemplo,

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

poderia ser usado para definir um tipo que permite que conjuntos matemáticos de naipes sejam representados como enum cardsuitoperações lógicas bit a bit.

C #

Os tipos enumerados na linguagem de programação C # preservam a maior parte da semântica de "inteiro pequeno" dos enums do C. Algumas operações aritméticas não são definidas para enums, mas um valor de enum pode ser convertido explicitamente em um inteiro e vice-versa, e uma variável de enum pode ter valores que não foram declarados pela definição de enum. Por exemplo, dado

enum Cardsuit
{
    Clubs,
    Diamonds,
    Spades,
    Hearts
}

as expressões CardSuit.Diamonds + 1e CardSuit.Hearts - CardSuit.Clubssão permitidas diretamente (porque pode fazer sentido percorrer a sequência de valores ou perguntar quantas etapas existem entre dois valores), mas CardSuit.Hearts * CardSuit.Spadesé considerado fazer menos sentido e só é permitido se os valores forem primeiro convertidos para inteiros .

C # também fornece o recurso semelhante ao C de ser capaz de definir valores inteiros específicos para enumerações. Fazendo isso, é possível realizar operações binárias em enumerações, tratando assim os valores de enumeração como conjuntos de sinalizadores. Esses sinalizadores podem ser testados usando operações binárias ou com o método embutido 'HasFlag' do tipo Enum.

A definição de enumeração define nomes para os valores inteiros selecionados e é um açúcar sintático , pois é possível atribuir a uma variável enum outros valores inteiros que não estão no escopo da definição de enum.

C ++

C ++ tem tipos de enumeração que são herdados diretamente de C e funcionam principalmente como esses, exceto que uma enumeração é um tipo real em C ++, fornecendo verificação adicional em tempo de compilação. Além disso (como acontece com structs), a enumpalavra-chave C ++ é automaticamente combinada com um typedef , de modo que, em vez de nomear o tipo enum name, simplesmente nomeie-o name. Isso pode ser simulado em C usando um typedef:typedef enum {Value1, Value2} name;

C ++ 11 fornece um segundo tipo de enumeração de tipo seguro que não é convertido implicitamente em um tipo inteiro. Ele permite que o fluxo de IO seja definido para esse tipo. Além disso, as enumerações não vazam, portanto, devem ser usadas com Enumeração Type::enumeration. Isso é especificado pela frase "enum class". Por exemplo:

enum class Color {Red, Green, Blue};

O tipo subjacente é um tipo integral definido pela implementação que é grande o suficiente para conter todos os valores enumerados (não precisa ser o menor tipo possível!). Em C ++, você pode especificar o tipo subjacente diretamente. Isso permite "encaminhar declarações" de enumerações:

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 a iotapalavra-chave para criar constantes enumeradas.

type ByteSize float64

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

Java

O J2SE versão 5.0 da linguagem de programação Java adicionou tipos enumerados cuja sintaxe de declaração é semelhante à de C :

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

O sistema de tipo Java, no entanto, trata as enumerações como um tipo separado dos inteiros, e a mistura de valores enum e inteiros não é permitida. Na verdade, um tipo enum em Java é, na verdade, uma classe especial gerada pelo compilador em vez de um tipo aritmético, e os valores enum se comportam como instâncias globais pré-geradas dessa classe. Os tipos de enum podem ter métodos de instância e um construtor (cujos argumentos podem ser especificados separadamente para cada valor de enum). Todos os tipos de enum estendem implicitamente a Enumclasse abstrata. Um tipo de enum não pode ser instanciado diretamente.

Internamente, cada valor enum contém um inteiro, correspondendo à ordem em que são declarados no código-fonte, começando em 0. O programador não pode definir um inteiro personalizado para um valor enum diretamente, mas pode-se definir construtores sobrecarregados que podem então atribuir valores arbitrários para membros autodefinidos da classe enum. A definição de getters permite o acesso a esses membros autodefinidos. O inteiro interno pode ser obtido a partir de um valor enum usando o ordinal()método, e a lista de valores enum de um tipo de enumeração pode ser obtida na ordem usando o values()método. Geralmente, não é recomendável que os programadores convertam enums em inteiros e vice-versa. Os tipos enumerados são Comparable, usando o inteiro interno; como resultado, eles podem ser classificados.

A biblioteca padrão Java fornece classes de utilitário para usar com enumerações. A EnumSetclasse implementa um Setde valores enum; ele é implementado como uma matriz de bits , o que o torna muito compacto e tão eficiente quanto a manipulação explícita de bits, mas mais seguro. A EnumMapclasse implementa um valor Mapde enum para o objeto. Ele é implementado como uma matriz, com o valor inteiro do valor enum servindo como o índice.

Perl

Linguagens digitadas dinamicamente na tradição sintática de C (por exemplo, Perl ou JavaScript ) não fornecem, em geral, enumerações. Mas na programação Perl, o mesmo resultado pode ser obtido com a lista de strings abreviadas e hashes (possivelmente fatias ):

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 conhecido como Perl 6) oferece suporte a enumerações. Existem várias maneiras de declarar enumerações em Raku, todas criando um 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

Enums foram adicionados no PHP versão 8.1.

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

Ferrugem

Embora Rust use a enumpalavra - chave como C, ele a usa para descrever uniões marcadas , das quais enums podem ser considerados uma forma degenerada. Os enums do Rust são, portanto, muito mais flexíveis e podem conter variantes de estrutura e tupla.

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

Rápido

Em C, as enumerações atribuem nomes relacionados a um conjunto de valores inteiros. Em Swift , as enumerações são muito mais flexíveis e não precisam fornecer um valor para cada caso da enumeração. Se um valor (denominado valor bruto ) for fornecido para cada caso de enumeração, o valor pode ser uma string, um caractere ou um valor de qualquer tipo inteiro ou de ponto flutuante.

Como alternativa, os casos de enumeração podem especificar valores associados de qualquer tipo a serem armazenados junto com cada valor de caso diferente, da mesma forma que as uniões ou variantes fazem em outras linguagens. Pode-se definir um conjunto comum de casos relacionados como parte de uma enumeração, cada um dos quais possui um conjunto diferente de valores de tipos apropriados associados a ele.

Em Swift, as enumerações são um tipo de primeira classe. Eles adotam muitos recursos tradicionalmente suportados apenas por classes, como propriedades computadas para fornecer informações adicionais sobre o valor atual da enumeração e métodos de instância para fornecer funcionalidade relacionada aos valores que a enumeração representa. Enumerações também podem definir inicializadores para fornecer um valor de caso inicial e podem ser estendidas para expandir sua funcionalidade além de sua implementação original; e pode estar em conformidade com os protocolos para fornecer funcionalidade padrão.

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

Ao contrário de C e Objective-C , os casos de enumeração Swift não recebem um valor inteiro padrão quando são criados. No exemplo do CardSuit acima, paus, ouros, copas e espadas não são implicitamente iguais a 0, 1, 2 e 3. Em vez disso, os diferentes casos de enumeração são valores completos em seu próprio direito, com um tipo explicitamente definido de CardSuit .

Vários casos podem aparecer em uma única linha, separados por vírgulas:

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

Ao trabalhar com enumerações que armazenam valores brutos de inteiros ou strings, não é necessário atribuir explicitamente um valor bruto para cada caso, porque o Swift atribuirá os valores automaticamente.

Por exemplo, quando inteiros são usados ​​para valores brutos, o valor implícito para cada caso é um a mais que o caso anterior. Se o primeiro caso não tiver um valor definido, seu valor será 0.

A enumeração abaixo é um refinamento da enumeração anterior do planeta, com valores brutos inteiros para representar a ordem de cada planeta a partir do sol:

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

No exemplo acima, Planet.mercury tem um valor bruto explícito de 1, Planet.venus tem um valor bruto implícito de 2 e assim por diante.

"Os detalhes são encontrados na documentação do Swift online aqui."

TypeScript

TypeScript adiciona um tipo de dados 'enum' ao JavaScript.

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

Por padrão, os enums numeram membros começando em 0; isso pode ser substituído definindo o valor do primeiro:

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

Todos os valores podem ser definidos:

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

TypeScript oferece suporte ao mapeamento do valor numérico para seu nome. Por exemplo, encontra o nome do valor 2:

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

alert(suitName);

Pitão

Um enummódulo foi adicionado à biblioteca padrão do Python na versão 3.4.

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

Também existe uma API funcional para criar enumerações com índices gerados automaticamente (começando com um):

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

Enumerações Python não impõem correção semântica (uma comparação sem sentido com uma enumeração incompatível sempre retorna False em vez de gerar um 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 tem apenas tipos enumerados para interoperabilidade com C; portanto, a semântica é semelhante a C e, como em C, os valores enum são apenas inteiros e nenhuma verificação de tipo adicional é feita. O exemplo C acima pode ser escrito em Fortran como

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

Visual Basic / VBA

Os tipos de dados enumerados no Visual Basic (até a versão 6) e VBA são atribuídos automaticamente ao Longtipo de dados " " e também se tornam um tipo de dados:

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

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

Exemplo de código em VB.NET

Enum CardSuit
    Clubs
    Diamonds
    Hearts
    Spades
End Enum

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

Lisp

Common Lisp usa o especificador de tipo de membro, por exemplo,

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

que afirma que o objeto é do tipo carduit se for um #'eqlclube, ouros, copas ou espadas. O especificador de tipo de membro não é válido como um especializador de parâmetro Common Lisp Object System (CLOS), no entanto. Em vez disso, (eql atom)que é o equivalente a (member atom)pode ser usado (ou seja, apenas um membro do conjunto pode ser especificado com um especificador de tipo eql, no entanto, pode ser usado como um especializador de parâmetro CLOS.) Em outras palavras, para definir métodos para cobrir um tipo enumerado, um método deve ser definido para cada elemento específico daquele tipo.

Adicionalmente,

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

pode ser usado para definir tipos enumerados arbitrários em tempo de execução. Por exemplo

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

referir-se-ia a um tipo equivalente à definição anterior de carduit, já que, é claro, simplesmente estaria usando

(member club diamond heart spade)

mas pode ser menos confuso com a função #'memberpor razões estilísticas.

Tipo de dados algébricos em programação funcional

Em linguagens de programação funcional na linhagem de ML (por exemplo, Standard ML (SML), OCaml e Haskell ), um tipo de dados algébrico com apenas construtores nulos pode ser usado para implementar um tipo enumerado. Por exemplo (na sintaxe de assinaturas SML):

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

Nessas linguagens, a representação de inteiro pequeno é completamente oculta do programador, se de fato tal representação for empregada pela implementação. No entanto, Haskell tem a Enum classe de tipo que um tipo pode derivar ou implementar para obter um mapeamento entre o tipo e Int.

Bancos de dados

Alguns bancos de dados oferecem suporte a tipos enumerados diretamente. O MySQL fornece um tipo enumerado ENUMcom valores permitidos especificados como strings quando uma tabela é criada. Os valores são armazenados como índices numéricos com a string vazia armazenada como 0, o primeiro valor da string armazenado como 1, o segundo valor da string armazenado como 2, etc. Os valores podem ser armazenados e recuperados como índices numéricos ou valores de string.

Exemplo:

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

Esquema XML

O esquema XML oferece suporte a tipos enumerados por meio da faceta de enumeração usada para restringir a maioria dos tipos de dados primitivos, como strings.

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

Veja também

Referências

links externos