Wstęp do programowania 2 wykład 1 rekordy z wyróżnikami Agata Półrola Wydział Matematyki UŁ 2005/2006
Egzamin z I roku - problemy Problemy z wczytywaniem danych: skip_line Problemy z obliczeniami: zerowanie zmiennych konwersja typów
Rekordy z wyróżnikami
Rekordy z wariantami rekordy z wariantami to takie rekordy, których zawartość (tj. liczba i rodzaj składowych) zależą od wartości jednego z pól wyróżnika w rekordzie można wyróżnić części: wyróżnik (discriminant) część stałą (invariant part) część wariantową (variant part)
Przykład type kategoria is (A, B, C, D, E, T); type tablica_kategorii is array (kategoria) of boolean; type osoba (kierowca:boolean) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case;
Część wariantowa musi znajdować się po części stałej składnia przypomina instrukcję case when wartość1 wartość2... wartość_n => pole : typ_pola; when wartość1.. wartość2 => pole : typ_pola; when others => pole : typ_pola; when others => null;
nie można deklarować pól o takich samych nazwach w różnych miejscach instrukcji wyboru type dni_tyg is (pon, wt, sw, czw, pt, sob, nie); type jakis_typ (k:dni_tyg) is record pole1,pole2:integer; case k is when sob nie => pole3 : float; when pon => pole3 : float; pole4 : integer; when others => null; end case; niepoprawne
Deklaracja typu i zmiennych Możliwość pierwsza: bez określania wartości wyróżnika (rekordy ograniczone - constrained records) type osoba (kierowca:boolean) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case; deklaracja zmiennej musi określić, jaką wartość ma wyróżnik sasiadka : osoba (false); -- notacja pozycyjna sasiad : osoba (kierowca => true);-- notacja nazywana
nadawanie wartości składowym rekordu jest standardowe: sasiadka.imie := "Kazimiera ; sasiadka.nazwisko:="kowalska "; można też użyć agregatu rekordu i notacji pozycyjnej albo nazywanej: sasiadka:= (false, "Kazimiera ", "Kowalska ", 1955); sasiad := (kierowca=>true, imie=>"jan ", nazwisko=>"kowalski ", rok_urodzenia=>1954, prawo_jazdy=>(true,true,others=>false)); (wartość wyróżnika występuje jeszcze raz w agregacie)
W przypadku powyższej deklaracji wartości wyróżnika nie można zmienić Jeśli chcemy móc modyfikować wartość wyróżnika, musimy nadać mu domyślną wartość w deklaracji typu rekordowego
Rekordy z wariantami: deklaracja typu i zmiennych z określeniem wartości wyróżnika (unconstrained records) type osoba (kierowca:boolean:=false) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case; deklaracja zmiennej nie musi zawierać żadnych dodatkowych informacji: sasiadka, sasiad, tesciowa : osoba;
nadawanie wartości składowym rekordu odbywa się jak poprzednio, przy użyciu notacji pozycyjnej albo nazywanej zmiana wartości wyróżnika możliwa jest tylko przy użyciu agregatu rekordu
-- prawidłowy sposób zmiany: tesciowa:=(kierowca=>true, imie=>"kleopatra ", nazwisko=> "Kowalska ", rok_urodzenia=> 1930, prawo_jazdy=>(c D T=>true, others=>false)); -- nieprawidłowo: tesciowa.kierowca :=true; tesciowa.imie:="kleopatra ";
Rekordowi możemy nadać wartość początkową już w chwili deklaracji ciotka_sasiada : osoba := (kierowca=>true, imie=>"eleonora ", nazwisko=>"kowalska ", rok_urodzenia=>1950, prawo_jazdy=>(b=>true,others=>false)); a mimo to pozostaje on rekordem "nie określonym", z możliwością zmiany wartości wyróżnika: ciotka_sasiada := (kierowca=>false, imie=>ciotka_sasiada.imie, nazwisko=>ciotka_sasiada.nazwisko, rok_urodzenia=>ciotka_sasiada.rok_urodzenia);
możliwe jest także nadawanie wartości wyróżnika przez podstawianie całych rekordów narzeczony_jasi : osoba := (true, "Jan ", "Iksinski ", (A B=>true,others=>false)); narzeczony_basi : osoba; -- domyślnie - nie ma prawa jazdy narzeczony_basi := narzeczony_jasi; -- nastąpiła nie tylko zmiana narzeczonego, -- ale i wyróżnika rekordu...
Posiadanie przez wyróżnik wartości domyślnej nie oznacza, że wszystkie zmienne tego typu są bez ograniczenia (unconstrained) możliwa deklaracja zmiennej: niemowlak : osoba (kierowca => false); zadeklarowana w ten sposób zmienna jest z ograniczeniem (constrained), wartość wyróżnika nie może być zmieniona
Cechy rekordów z wariantami wyróżnik rekordu traktowany jest jak normalne pole, można się do niego odwoływać: if sasiad.kierowca=true then... próby odwołania do nie istniejących przy danej wartości wyróżnika pól powodują wystąpienie błędu Constraint_Error
Atrybut constrained atrybut 'Constrained (sposób użycia: zmienna'constrained) przyjmuje wartość true, gdy dany rekord jest "określony" (constrained - nie można zmienić wartości jego wyróżnika), a false - w przeciwnym przypadku. if not ktos'constrained then ktos:=(kierowca=>...,...); end if; -- zmiana wartości wyróżnika tylko wtedy, gdy jest to możliwe, -- mimo ew. ostrzeżeń w czasie kompilacji -- nie będzie błędu wykonania
Typy rekordowe z wieloma wyróżnikami Można deklarować typy rekordowe z wariantami posiadające więcej niż jeden wyróżnik. Mogą one jednak posiadać tylko jedną część wariantową; kolejne konstrukcje case mogą być w niej zagnieżdżone. Przy ich tworzeniu obowiązują dotychczasow zasady
-- nieprawidłowa definicja -- dwie części wariantowe type osoba1 (plec:p; kierowca:boolean) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case plec is when K => nazwisko_panienskie: string(1..10):=(others=>' '); when M =>null; end case; case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case;
-- nieprawidłowa definicja - powtarzające się nazwy pól type osoba2 (plec:p; kierowca:boolean) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case plec is when K => nazwisko_panienskie: string(1..10):=(others=>' '); case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case; when M => case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case; end case;
-- definicja prawidlowa type osoba2 (plec:p; kierowca:boolean) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case plec is when K => nazwisko_panienskie: string(1..10):=(others=>' '); case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case; when M => case kierowca is when true => pj: tablica_kategorii; when false => null; end case; end case;
type osoba1 (plec:p; kierowca:boolean) is record dane : os(plec); case kierowca is when true => prawo_jazdy: tablica_kategorii; when false => null; end case; Jak to zadeklarować ładniej type os (pl: p) is record imie, nazwisko: string (1..10):=(others=>' '); rok_urodzenia: positive; case pl is when K => nazwisko_panienskie: string(1..10):=(others=>' '); when M =>null; end case;
Jeśli wyróżniki niezależne... (dość ładnie bez sztuczek) type pies (rasowy:boolean; medalista:boolean) is record imie:string(1..10); wlasciciel:string(1..20); case rasowy is when true => rodzaj: rodzaj_psa; rasa: string(1..10); case medalista is when true => ilosc_medali:positive; when false => null; end case; when false=> null; end case;
Agregaty rekordów pies1 : pies := (rasowy=>false, medalista=>false, imie=>"azor ", wlasciciel=>"jan Kowalski "); pies2 : pies := (rasowy=>false, medalista=>true, imie=>"burek ", wlasciciel=>"jan Kowalski "); pies3 : pies := (rasowy=>true, medalista=>false, imie=>"cezar ", wlasciciel=>"jan Kowalski ", rodzaj=>mysliwski, rasa=>"foksterier"); pies4 : pies:= (rasowy=>true, medalista=>true, imie=>"funia ",wlasciciel=>"jan Kowalski ", rodzaj=>pokojowy, rasa=>"pekinczyk ", ilosc_medali=>10);
W przypadku wielu wyróżników także możemy deklarować rekordy z ograniczeniem i bez ograniczenia Jeśli jeden wyróżnik ma wartość domyślną, muszą mieć ją również pozostałe
Inne zastosowanie wyróżników rekordy ze składowymi o zmiennym rozmiarze Innym zastosowaniem wyróżników jest określanie za ich pomocą rozmiaru składowych rekordu, np. długości łańcucha czy rozmiaru tablicy
type dane (dl_nazwy:positive) is record zaklad_pracy:string(1..dl_nazwy); rok_zalozenia: positive; type osoba is record imie, nazwisko:string(1..10); rok_ur:positive; type tabela_pracownikow is array (positive range <>) of osoba; type firma (il_pracownikow:positive) is record nazwa_firmy : string(1..20); zatrudnieni : tabela_pracownikow (1..il_pracownikow);
W obu przykładach jedno z pól rekordu należy do niezawężonego typu tablicowego. Jeśli wyróżnik nie ma wartości domyślnej, to musimy podać ją przy deklaracji zmiennej zaklad1 : dane(dl_nazwy=>50); zaklad2 : dane(20); zaklad3 : dane := (dl_nazwy=>13, zaklad_pracy=>"wks Mostostal", rok_zalozenia=> 1974); powyższe zmienne nie mogą zmieniać wartości wyróżnika, a więc i rozmiaru swoich składowych (są z ograniczeniem )
type dane (dl_nazwy:positive:=20) is record zaklad_pracy:string(1..dl_nazwy); rok_zalozenia: positive; jeżeli wyróżnik ma wartość domyślną, to możliwe są dwa rodzaje deklaracji: zmienne z ograniczeniem: zaklad1 : dane(dl_nazwy=>50); zaklad2 : dane(20); zmienne bez ograniczenia zaklad3 : dane; -- domyślna wartość wyróżnika - 20 zaklad4 : dane:= (dl_nazwy=>13, zaklad_pracy=>"wks Mostostal", zaklad3 := zaklad4; -- zmiana długości z 10 na 13 rok_zalozenia=> 1974);
podobnie jak poprzednio wyróżników może być więcej niż jeden. Mogą się one odnosić do tego samego lub do różnych pól rekordu.
type tabela_pracownikow is array (positive range <>) of osoba; type firma (dl_nazwy,il_pracownikow:positive) is record nazwa_firmy : string(1..dl_nazwy); zatrudnieni : tabela_pracownikow (1..il_pracownikow); f1 : firma(dl_nazwy=>3, il_pracownikow=>10); f2 : firma(12,5);
Inne zastosowanie wyróżników inicjowanie wartości pola rekordu type ograniczenie (predkosc:natural) is record max_predkosc : natural := predkosc; obszar_zabudowany : ograniczenie(60);... put (obszar_zabudowany.max_predkosc); -- wypisze 60 obszar_zabudowany.max_predkosc:=50; put (obszar_zabudowany.max_predkosc); -- wypisze 50
Inne zastosowanie wyróżników określenie pola rekordu będącego polem definiowanego rekordu type tabela_pracownikow is array (positive range <>) of osoba; type firma (il_pracownikow:positive) is record nazwa_firmy : string(1..20); zatrudnieni : tabela_pracownikow (1..il_pracownikow); type pracodawca (ilosc_zatrudnionych:natural) is record imie,nazwisko : string(1..10); jego_firma : firma(ilosc_zatrudnionych);
Inne zastosowanie wyróżników tworzenie rekordów o polach zachowujących się jak stałe type plec is (M, K); -- plec i rok urodzenia nie moga sie zmienic, -- waga i wzrost - tak type czlowiek (p: plec;rok_urodzenia:positive) is record waga, wzrost: positive; Iksinski:czlowiek(p=>M, rok_urodzenia=>1966);... -- niedozwolone Iksinski:=(p=>M, rok_urodzenia=>1965, wzrost=>187, waga=>99);