, <, <=, >=, =, /=).
Typy wyliczeniowe możemy definiować sami, pisząc w części deklaracyjnej programu
type nazwa_typu is (element_1, ..., element_n);
Elementy typu wyliczeniowego nazywamy literałami wyliczeniowymi. Mogą być nimi identyfikatory lub znaki (ujęte w apostrofy) np.
-- identyfikatory
type dni is (pon, wt, sr, czw, pt, so, nie);
-- znaki
type liczby_rzymskie is ( 'I', 'V', 'X', 'L', 'C', 'D', 'M');
-- znaki i identyfikatory
type xxx is (r2, 'a', xxxd12);
W celu wprowadzania i wyprowadzania wartości typu wyliczeniowego musimy skonkretyzować pakiet ada.text_io.enumeration_io dla danego typu, np.
package dni_io is new ada.text_io.enumeration_io(dni);
package rzymskie_io is new
ada.text_io.enumeration_io(liczby_rzymskie);
Zauważmy, że konkretyzacji trzeba dokonać nawet wtedy, gdy elementami typu wyliczeniowego są same znaki (wyprowadzane i wprowadzane są wtedy znaki ujęte w apostrofy).
Oto przykład deklaracji i użycia takiego typu:
-- przyklad uzycia typow wyliczeniowych
-- wprowadzanie i wyprowadzanie elementow tego typu
with ada.text_io;
use ada.text_io;
procedure pr17 is
type pierwiastki is (H, He, Li, Be, B, C, N, O, F, Ne,
Na, Mg, Al);
-- pierwiastki sa uporzadkowane rosnaco wg mas atomowych
package chemia_io is new
ada.text_io.enumeration_io(pierwiastki);
p1,p2:pierwiastki;
begin
put_line("Nasza lista obejmuje nastepujace pierwiastki
chemiczne :");
put_line("Al, B, Be, C, F, H, He, Li, N, Na, Ne, Mg, O");
new_line;
put("podaj nazwy dwoch pierwiastkow, a dowiesz sie, ktory ma
wieksza mase atomowa");
new_line;
put(" 1 : ");chemia_io.get(p1);
put(" 2 : ");chemia_io.get(p2);
if p1>p2 then
chemia_io.put(p1);
put(" ma wieksza mase atomowa niz ");chemia_io.put(p2);
elsif p1
chemia_io.put(p1);
put(" ma mniejsza mase atomowa niz");chemia_io.put(p2);
else
put("podane pierwiastki maja rowne masy atomowe");
end if;
end pr17;
Wykonując program zobaczymy, że symbole pierwiastków wyprowadzane są trochę nieprawidłowo, bo wielkimi literami. W wypadku literałów wyliczeniowych Ada, podobnie jak w wypadku identyfikatorów, nie rozróżnia rozmiarów liter. Za sposób wyprowadzania natomiast odpowiada parametr procedury chemia_io.put (tzn. procedury put dla konkretnego typu wyliczeniowego) o nazwie Set. Może on przyjmować dwie wartości - Upper_Case (ustawioną jako domyślną - wtedy elementy typu wyprowadzane są wielkimi literami) i Lower_Case. Procedura put ma jeszcze jeden parametr - width, odpowiadający za szerokość wyprowadzanego tekstu, lecz ponieważ ma on domyślnie wartość 0, więc wyprowadzany element typu zajmuje tylko tyle miejsca, ile musi.
Podtypy
Jeżeli mówimy o definiowaniu własnych typów, wypada wspomnieć także o definiowaniu podtypów. Podtyp nie jest nowym typem, stanowi jedynie podzbiór wartości pewnego już znanego typu (nazywanego tutaj typem bazowym). Definiujemy go pisząc w części deklaracyjnej programu
subtype nazwa_podtypu is typ_bazowy range
ograniczenie_dolne .. ograniczenie_górne;
gdzie ograniczenie_dolne i ograniczenie_górne należą do typu bazowego, np.
subtype dni_robocze is dni range pon .. pt;
subtype wiek_ludzki is integer range 0..120;
Granice zakresu mogą być także obliczane:
granica_gorna:=12*5+3;
subtype ograniczony_integer is
integer range 1 .. granica_gorna;
n:integer:=4;
subtype wiekszy_integer is integer range 1 .. 12*n+3;
Podanie jako element_k lub element_n elementów spoza zakresu typu bazowego spowoduje podczas wykonywania programu zgłoszenie błędu constraint_error - przekroczenia zakresu. Można oczywiście definiować podtypy tak, aby obejmowały cały zakres typu bazowego, np.
subtype calkowite is integer;
co powoduje, że calkowite jest właściwie inną nazwą typu integer; a także podtypy będące podtypami pewnego podtypu, np.
subtype dni_robocze is dni range pon .. pt;
subtype srodek_tygodnia is dni_robocze range wt .. czw;
Podtyp nie jest nowym typem, a więc dziedziczy właściwości swojego typu bazowego. I tak na przykład jeżeli odpowiednią konkretyzacją pakietu ada.text_io.enumeration_io zapewniliśmy wykonywanie operacji wejścia/wyjścia dla elementów typu dni, to nie musimy już dokonywac kolejnej konkretyzacji dla typów dni_robocze ani srodek_tygodnia - odpowiadać za to będzie ten sam pakiet, co w przypadku typu dni. Jak wiadomo, nie wolno w jednym wyrażeniu łączyć ze sobą elementów należących do różnych typów. Jednak łączenie w jednym wyrażeniu elementów należących do różnych podtypów tego samego typu bazowego jest dozwolone.
Nazw podtypów możemy używać zamiast zakresów w teście członkostwa. Zamiast pisać np. w instrukcji warunkowej
wiek in 0..120
możemy napisać
wiek in wiek_ludzki.
Oprócz poznanej definicji podtypu możemy definiować podtypy w sposób niejawny. Nie mają one wówczas nazwy, stanowia jedynie zawężenie zakresu pewnego typu. Dokonujemy tego równocześnie z deklaracją zmiennej, np.
wiek_dziecka: integer range 0..18;
Zmienna o nazwie wiek_dziecka może przyjmować wartości typu integer, ale z określonego przedziału - od 0 do 18. Napisanie np.
wiek_dziecka:=19;
spowoduje zgłoszenie błędu constraint_error.
W Adzie istnieją predefiniowane podtypy typu integer - positive i natural. Określone są one następująco:
subtype positive is integer range 1..integer'last;
subtype positive is integer tange 0..integrer'last;
Wspominaliśmy już o nich przy okazji omawiania zakresów typów liczbowych.
A oto przykładowy program:
-- program przedstawiajacy definiowanie podtypow
with ada.text_io;
use ada.text_io;
procedure pr18 is
type szczyty_tatrzanskie is ( Bobrowiec, Giewont, Kasprowy,
Wolowiec, Bystra, Swinica, Krywan,
Rysy, Lomnica, Gerlach);
subtype Tatry_Zachodnie is szczyty_tatrzanskie
range Bobrowiec .. Bystra;
subtype Tatry_Wysokie is szczyty_tatrzanskie
range Swinica .. Gerlach ;
package szczyty_io is new
ada.text_io.enumeration_io (szczyty_tatrzanskie);
use szczyty_io;
package int_io is new ada.text_io.integer_io(integer);
use int_io;
najwyzszy_Tatry: constant szczyty_tatrzanskie:=Gerlach;
najwyzszy_Polska: constant szczyty_tatrzanskie:=Rysy;
najwyzszy_Tatry_Wysokie:constant Tatry_Wysokie
:=najwyzszy_Tatry;
najwyzszy_Tatry_Zachodnie: constant Tatry_Zachodnie :=Bystra;
gora1,gora2:szczyty_tatrzanskie;
punkty:integer range 0..10;
begin
punkty:=0;
set_col(20);
put_line("*** SZCZYTY TATRZANSKIE ***");
new_line;
set_col(5);
put_line("Bobrowiec, Bystra, Gerlach, Giewont,
Kasprowy, Krywan, ");
set_col(15);
put_line("Lomnica, Rysy, Swinica, Wolowiec");
new_line;
put_line("Test znajomosci Tatr - mozesz podawac tylko
powyzsze szczyty");
put("Podaj nazwe najwyzszego szczytu Tatr : ");
get(gora1);
if gora1=najwyzszy_Tatry then punkty:=punkty+1;end if;
put("Podaj nazwe najwyzszego szczytu w Polsce : ");
get(gora1);
if gora1=najwyzszy_Polska then punkty:=punkty+1;end if;
put_line("Podaj nazwy dwoch szczytow w Tatrach Zachodnich
- najpierw nizszy ");
put(" 1 : ");get(gora1);
put(" 2 : ");get(gora2);
if gora1 in Tatry_Zachodnie then punkty:=punkty+1;end if;
if gora2 in Tatry_Zachodnie'first..Tatry_Zachodnie'last then
punkty:=punkty+1;
end if;
if gora1
put_line("Podaj nazwy dwoch szczytow w Tatrach Wysokich
- najpierw nizszy ");
put(" 1 : ");get(gora1);
put(" 2 : ");get(gora2);
if gora1 in Tatry_Wysokie then punkty:=punkty+1;end if;
if gora2 in Tatry_Wysokie then punkty:=punkty+1;end if;
if gora1
put("Podaj nazwe najwyzszego szczytu Tatr Zachodnich : ");
get(gora1);
if gora1=najwyzszy_Tatry_Zachodnie then punkty:=punkty+1;
end if;
put("Podaj nazwe najwyzszego szczytu Tatr Wysokich : ");
get(gora1);
if gora1=najwyzszy_Tatry_Wysokie then punkty:=punkty+1;end if;
new_line;
put(ascii.bel);
if punkty>7 then
put_line("Gratulacje - Tatry znasz bardzo dobrze...
albo dobrze czytasz mapy");
put("Zdobyles ");put(punkty,width=>0);put(" pkt");
else
put("Nie znasz geografii Tatr - przykro mi ...");
put("Zdobyles tylko ");put(punkty,width=>0);put(" pkt");
end if;
end pr18;