MC102 |
TIPOS ENUMERADOS |
Suponha que tenhamos uma variável que só possa assumir um dentre um conjunto de valores. Por exemplo, suponha que estejamos criando um registro de pessoas que conhecemos para, por exemplo, fazer um programa que nos lembre de seus aniversários.
Assim, cada pessoa ou é parente, ou amigo. Então, como marcaríamos se a pessoa é um ou outro? Poderíamos associar a cada pessoa uma variável booleana que assumisse true se a pessoa é parente e false se é amigo. Isso funcionaria. Mas, e se, além desses, quisermos incluir os colegas, ou seja, a pessoa ou é parente, ou amigo, ou colega?
Poderíamos associar um número a cada tipo de pessoa: 0 para parente, 1 para colega e 2 para amigo, ou seja, construímos a tabela:
Código | Tipo |
---|---|
0 | |
1 | |
2 | |
Nada mnemônico, não é mesmo? Será que há como fazer melhor? Há. Podemos criar um tipo enumerado:
TYPE pessoa = (parente, amigo, colega); VAR p : pessoa; |
Aqui criamos um tipo, chamado pessoa, que aceita apenas um dos valores da lista e, em seguida, declaramos uma variável desse tipo. Como fazemos para abastecer um valor nessa variável?
BEGIN p := amigo; p := parente; p := colega; p := conhecido {erro de compilação} END. |
De fato, o compilador representa esses 3 valores como 0, 1 e 2. Exatamente como nossa tabela acima. A vantagem do uso de enumerações é que, além do código ficar mnemônico, ele ocupa menos espaço na memória pois, para guardar 0, 1 e 2 na memória 1 byte é suficiente, enquanto que para guardar um inteiro são necessários de 4 a 8 bytes, dependendo da máquina.
Naturalmente, não podemos declarar nada com os nomes dos valores usados na lista, pois eles são tidos como identificadores. Se tentarmos declarar algo com o mesmo nome o compilador acusará um erro. Por exemplo, o programa a seguir está errado:
TYPE estado = (estudante, faculdade, docente); {certo} naoAdministrativo = (estudante, professor); {declaração duplicada de "estudante"} VAR faculdade : estado; {declaração duplicada de "faculdade"} BEGIN estudante := 2; {estudante não é variável, é valor} END. |
Veja que não precisamos, de fato, criar uma enumeração para obter o resultado, bastaríamos criar constantes. Por exemplo, o seguinte programa tem o mesmo efeito do programa inicialmente desenvolvido:
CONST parente = 0; amigo = 1; colega = 2; VAR p : integer; BEGIN p := amigo; p := parente; p := colega; p := conhecido {erro de compilação} END. |
Mas, apesar disso, a vantagem de usar enumerações é que estou atrelando os valores ao tipo da variável. Por exemplo, em:
TYPE pessoa = (parente, amigo, colega); VAR p : pessoa; |
só posso por "q := parente" se "q" for do tipo "pessoa".
Devido ao modo como o Pascal representa as listas enumeradas (mostrado acima), os valores nestas são ordenados. Assim, no nosso exemplo, parente < amigo < colega.
Esses valores, justamente por serem ordenados, podem ser usados dentro de um FOR:
FOR p:=parente TO colega DO ou FOR p:=colega DOWNTO parente DO |
PRED E SUCC |
Como fazemos se quisermos determinar o predecessor e o sucessor de um tipo enumerado? Usamos Pred e Succ. Considere o exemplo:
TYPE digitos = (zero, um, dois, tres, quatro, cinco, seis, sete, oito, nove); cores = (azul, vermelho, verde); VAR x : digitos; y : digitos; c : cores; z : cores; BEGIN y := dois; x := Pred(y); {x recebe "um"} y := Succ(y); {y recebe "tres"} c := Pred(verde); {c recebe "vermelho"} z := Succ(c); {z recebe "verde"} END. |
Essas funções não trabalham só com tipos enumerados, mas também com qualquer tipo escalar que seja ordenado, exceto real. Assim:
VAR x : integer; a : boolean; BEGIN x := Pred(6); {x recebe 5} a := Succ(false) {a recebe "true"} END. |
Mas, e se eu estiver no limite? Ou seja, quanto valem Pred(zero) ou Succ(nove) no exemplo acima? Bom, esses valores não estão definidos, ou seja, darão erro.
Agora, suponha que temos uma lista enumerada e queremos saber a posição de cada valor na lista:
TYPE pessoa = (parente, amigo, colega); VAR p : pessoa; x : integer; BEGIN x := Ord(amigo); {x recebe 1} END. |
Isso mesmo! Ord serve também para dar a posição de determinado valor em uma lista enumerada. Assim, podemos imprimir a tabela criada pelo computador da seguinte maneira:
TYPE pessoa = (parente, amigo, colega); VAR p : pessoa; x : integer; BEGIN FOR p:= parente TO colega DO write(Ord(p),' ') END. |
Esse programa imprime:
0 1 2 |