Typ Wyliczeniowy

Witam, dzisiaj przedstawię Wam typ wyliczeniowy. Chcielibyśmy na przykład mieć jakąś zmienną, która przechowywałaby nam dni tygodnia-przypisywalibyśmy jej wartości od 1 do 7 włącznie. Jednakże nie jest to za dobre rozwiązanie, ponieważ istnieje możliwość przypisanie tej naszej zmiennej wartości mniejszej/większej niż 1-7, a poza tym przypisywanie jedynek, dwójek, trójek itd. jako nazwy miesięcy nie byłoby czytelne. Co zrobić w takim wypadku? Można zdefiniować stałe. Spójrzcie na poniższy przykład:

Po takiej definicji można się odwoływać do poszczególnych dni tygodnia:

Jednakże, w ten sposób możemy przypisywać wartości każdej zmiennej typu Integer, poza tym, gdy np. będziemy do jakiejś naszej procedury przesyłali wartości w ten sposób, to nadal istnieje możliwość wyjścia poza zakres ‘tygodnia’. Jest jednak inne wyjście, dużo bardziej wygodne. Popatrzcie:

Jak widzicie to wszystko jest bardzo proste. Musimy sobie najpierw utworzyć dowolną zmienną (typu TMiesiace) i do niej przypisywać wartości. Zawsze należy pamiętać, że jeżeli będziemy chcieli przypisać naszej zmiennej element, który nie istnieje, kompilator powiadomi nas o błędzie. Chciałbym zaznaczyć, że można deklarować zarówno nowe typy wyliczeniowe jak i zmienne wyliczeniowe. Jaka jest różnica, chyba się domyślacie. Popatrzcie:

Teraz, aby używać typu wyliczeniowego zadeklarowanego w sekcji type, musimy sobie utworzyć nową zmienną tego typu, ponieważ nie możemy operować bezpośrednio na naszym typie, tak samo, jak na typie podstawowym np. Integer

Natomiast używanie naszego typu wyliczeniowego z sekcji var to nic innego jak używanie zwykłej zmiennej. Nie możemy tworzyć nowych zmiennych o typie Dni, ponieważ taki typ nie istnieje – istnieje tylko zmienna o nazwie Dni, która ma określoną ilość możliwych do jej przypisania elementów :

Jak widać, różnica pomiędzy typami wyliczeniowymi deklarowanymi w sekcji type i bloku var jest intuicyjna. W type deklarujemy wtedy, kiedy wiemy, że w programie będzie nam potrzebny nowy typ, to znaczy będziemy deklarować kilka/kilkanaście/kilkadziesiąt itd. zmiennych tego naszego nowego typu. W var deklarujemy, kiedy potrzebna nam jest tylko jedna zmienna z listą wyliczeniową.

Trzeba Wam teraz jeszcze wiedzieć, że elementy typów wyliczeniowych są numerowane(jeżeli my sami się o to nie zatroszczymy) od zera, więc Styczen = 0, a Listopad = 10. Jeżeli jednak zapiszemy deklarację w ten sposób:

to wartości poszczególnych elementów będą wynosić: Styczen = 10, Luty = 11 , Marzec = 15 , Kwiecien = 16 , … , Wrzesien = 21 , Pazdziernik = 100, Listopad = 101 i Grudzień 201. Dzieje się tak, dlatego, że jeżeli przypiszemy elementowi wcześniejszemu wartość X, to następny element będzie o 1 większy od X.

Aby sprawdzić, jaką wartość ma jeden ze składników typu wyliczeniowego lub jaka jest aktualna wartość jakiegoś obiektu naszego typu możemy się posłużyć funkcją ORD:

Lub wykonać rzutowanie:

Musicie zapamiętać jedną, ważną rzecz: nie wolno przypisywać elementu zmiennej (np. Miesiace) w ten sposób:

próba takiego porównania też będzie błędna :

Wolno jedynie przypisywać i porównywać wartości w ten sposób:

Można też wykonać rzutowanie:

Składniki typu wyliczeniowego można też używać w pętlach:

W Memo1 ujrzymy kolejne indeksy.

Przydać się mogą także funkcje: Pred, zwracająca wartość poprzedniego elementu oraz Succ – zwracająca wartość następnego elementu oraz procedury: Inc zwiększająca i Dec zmniejszająca o podaną wartość(domyślnie o 1):

Jeszcze dwie uwagi. Jeżeli mamy taki typ wyliczeniowy:

to tak, jakbyśmy mieli tablice [Pon..Niedz] czyli [0..6]. Każdemu z elementów tej tablicy przyporządkowany jest identyfikator: 0-Pon, 1-Wto…6-Niedz. Jeżeli jednak, tak zapiszemy powyższą deklarację:

To będziemy mieli tablicę [0..23]. Tylko niektórym jej elementom przyporządkowany jest identyfikator, np. 0-Pon, 5-Wto itd. A co z pozostałymi? Czy nie można ich używać? Można, są to nienazwane elementy, przez które można się odwoływać jedynie za pomocą funkcji Pred, Succ, Inc i Dec, które omówiłem powyżej, lub przez rzutowanie:

Poza tym, jeżeli w ten sposób napiszemy deklarację:

to jaka będzie ilość elementów możliwych do przypisania(o różnych wartościach)? Tylko dwa-0 i 1, tablica będzię dwuelementowa: [0..1], z tym, żę drugiemu elementowi zostanie przyporządkowane aż 6 identyfikatorów.

Typy wyliczeniowe przydają się także podczas wysyłania argumentów do procedury lub funkcji, np.:

Mamy pewność, że do procedury(lub funkcji) nie zostanie wysłane nic innego, niż znajduje się w zakresie typu wyliczeniowego. W przeciwnym razie kompilator powiadomi nas o błędzie.
W przypadku funkcji możemy też zwracać jej wynik, który będzie mógł przyjąć wartość tylko jednego z elementów typu wyliczeniowego. To tyle na temat typów wyliczeniowych.

Typ okrojony

Typ okrojony pozwala wyeliminować dane spoza zakresu. Na przykład, zamiast używać zmiennej Integer do przechowywania numerów miesięcy, można użyć zmiennej o nazwie np.: Miesiace, która będzie okrojonym zakresem liczb całkowitych:

Teraz taka instrukcja zostanie uznana za błąd przez kompilator:

Dodam, że typ, jaki używany jest do reprezentowania numerów przydzielonych miesiącom nazywamy typem bazowym(Integer) dla typu okrojonego. Jeżeli chcielibyśmy, aby typem bazowym był np. typ Char, to moglibyśmy zadeklarować zmienną przechowującą
np. wielkie litery:

Oczywiście można też deklarować typy okrojone na podstawie typów wyliczeniowych:

Jak widzicie typ okrojony TDo_szkoly zadeklarowano jako podzbiór typu wyliczeniowego TDni_tygodnia. Typów okrojonych można używać jak typów wyliczeniowych (też jako argumenty funkcji itp.).

Koniec. Mam nadzieję, że wszystko jest zrozumiale wyjaśnione. W razie pytań zapraszam na forum, w razie sugestii/zauważonych błędów-piszcie na iskar_pk@wp.pl

Autor: Iskar