Rekordy

Oprócz omawianych już typów strukturalnych takich jak tablice, zbiory i pliki, można jeszcze wyróżnić takie typy złożone jak rekordy oraz obiekty. Obiektom poświęcimy następny wykład.
        typ strukturalny         +---------+ 
        ------------------------>|  array  |
           |                ^    +---------+
           |   +---------+  |    |  set    |
           +-->| packed  |--+    +---------+
               +---------+       |  file   |
                                 +---------+
                                 |  record |
                                 +---------+
                                 |  object |--------->
                                 +---------+
         
Definicja syntaktyczna typu rekordowego, który będziemy teraz omawiać, jest następująca.
typ rekordowy
-------------->(  record   )-----------------^-->(  end  )----->
                             |               |
                             +-[ Lista pol ]-+
Pola rekordu mogą być dowolnego typu. Jest to cecha, która różni zasadniczo, rekord od tablicy.
Lista pól
|                     
+--[ Cześć stała ]-------------------------------------------------------->
  |                   |         ^                           ^   |          ^
  |                   |         |                           |   |          |
  |                   +---( ; )--->[ Część wariantowa ]->+   +-->( ; )--+ 
  |                             ^
  +---------------------------->+
Stała część rekordu zbudowana jest z listy nazw (identyfikatorów) pól oraz ich typów. Oddzielają je średniki.
Część stała
-----------------[ Lista nazw ]---( : ) [ typ ]------------->
    ^                                               |
    |                                               |
    +<---------------------(  ;  )<-----------------+ 
Każde pole zawiera informację, którą można zawsze uzyskać w ten sam sposób.

Przykład.

type
      Data=record
         dzien : 1..31;
        miesiac: (St,Lu,Ma,Kw,Ma,Cz,Li,Si,Wr,Pa,Li,Gr);
            rok: integer
      end;
type
      zespolona=record
             re, im: real
      end;
      Osoba=record
         Nazwisko: string;
         Imie    : string;
         DataUrodzenia: Data;
         plec    : (mezczyzna,kobieta);
         StanCywilny    : (wolny,zonaty,owdowialy,rozwiedziony)
      end;
Za pomocą konstruktora rekordowego można utworzyć wartość danego typu i przypisać ją jakiejś zmiennej tegoż typu. Jażeli, przykładowo, mamy zmienne
z: zespolona;
d: Data;
o: Ossoba;
to konkretne wartości można przypiszć następująco:
z:=zespolona(1.0.,-1.0);
d:=Data(1,St,1999);
o:=Osoba('Wirth','Chris',Data(18,St,1966),mezczyzna,wolny);
Można to przedstawić na diagramach następująco.
+--------------+   +---------------+     +---------------+
|        1.0   |   |            1  |     |   Wirth       |
+--------------+   +---------------+     +---------------+
|       -1.0   |   |           St  |     |   Chris       |
+--------------+   +---------------+     +---------------+
                   |         1999  |     | 18|  St | 1996|
                   +---------------+     +---------------+
                                         |  mezczyzna    |
                                         +---------------+
                                         |  wolny        |
                                         +---------------+
   zespolona z          Data d               Osoba o
Jak dotrzeć do poszczególnych pól rekordu? Jeśli zmienna x jest typu rekordowego T, a s jest nazwą pola rekordu, to
x.s:=xi
oznacza przypisanie polu s tegoż rekordu, wartości xi. Typ xi i typ pola x rekordu są takie same. W przykładach, które były podane wyżej mamy
                                typ
z.im                           (real)
d.miesiac                      (St, ..., Gr)
o.nazwisko                     (string)
o.DataUrodzenia                (Data)
o.DataUrodzenia.Dzien          (1..31)
itd.
(Proszę zwrócić uwagę na złożoność struktury Osoba, która zawiera Datę, itd. )
var a      :  array[1..N] of Osoba;
    licznik:  integer;
begin
   licznik:=0;
   for i:=1 to N do
      if (a[i].plec=kobieta) and (a[i].stancywilny=wolny) then
         licznik:=licznik+1;
end;
(*  liczba kobiet w stanie wolnym zapisanych w tablicy a  *)
Inny sposób dostępu do pól rekordu polega na użyciu instrukcji wiążącej
with
with. Przytoczony wyżej fragment programu ustalającego liczbę kobiet w stanie wolnym, można z jej pomocą zapisać następująco:

Przykład.

var a      :  array[1..N] of Osoba;
    licznik:  integer;
begin
   licznik:=0;
   for i:=1 to N do
      with a[i] do
      if (plec=kobieta) and (stancywilny=wolny) then
         licznik:=licznik+1;
end;
(*  liczba kobiet w stanie wolnym zapisanych w tablicy a  *)
Konstrukcja with r do s oznacza, że można używać nazw selektorów pól zmiennej rekordowej r bez poprzedzania ich nazwą zmiennej, ponieważ wiadomo, że będą się do niej odnosiły. Skraca to tekst programu i zapobiega wielokrotnemu wyliczaniu od nowa składowej indeksowanej a[i]. Poniższy program stosuje strukturę rekordu do reprezentowania liczb zespolonych

Rekordy z wariantami

Czasami wygodnie jest korzystać z tzw. rekordów z wariantami. Tak jest np. w przypadku współrzędnych punktu płaszczyzny. Czasami potrzebna jest ich postać biegunowa, z czasami kartezjańska. rekordy wariantowe pozwalają na przechowywanie w nich takich lub innych informacji w zależności od sytuacji. Dla rozpoznania wariantu (rodzajy współrzędnych) potrzebujemy dodatkowego wyróżnika, wielkości, która przyjmuje odpowiednie wartości odróżniające występujące sytuacje (tak jak to jest w przypadku współrzędnych kartezjańskich lub biegunowych). Wyróżnik typu nazywa się też polem wariantowym.
[ Czesc wariantowa ] 
|
+--(  case  )-------------------------[ typ pola   ]--( of )-->[ wariant ]--->  
             |                     ^    wyróżnika          ^             |
             |                     |                         |             |
             +->[ nazwa ]-->( : )--+                         |             |
                                                             +-( ; )<------+
typ pola wyróżnika
|
-------------->[  Identyfikator typu wyliczeniowego ]----->
wariant
|
+---->[ stała ]---->( : )----( ( )----------------->( ) )----->
 ^               |                  |            |
 |               |                  +->[ Lista ]-+
 +----(  ,  )----+                       pól
Na podstawie diagramu widzimy, że każdy wariant identyfikowany jest przez conajmniej jedną stałą. Stałe muszą być różne i muszą być typu wyliczeniowego zgodnego z typem pola wyróżnika. Identyfikator pola wyróżnika jest opcjonalny.

Przykład.

type
   Wspolrzedne=record
        case rodzaj:(kartezjanskie,biegunowe) of
             kartezjanskie:(x,y :real);
             biegunowe    :(r,fi:real)
   end;
Nazwą pola znacznikowego jest w tym wypadku rodzaj, a współrzędne mają nazwy x, y lub r, fi w zależności od rodzaju. Typ Osoba, który został zdefiniowany poprzednio, zawiera informacje dotyczące płci osób itp. Można tam również umieścić informację ozaroście, w przypadku mężczyzn oraz o trzech wymiarach sylwetki kobiecej (Przykład z Wirtha). Dobrze jest zredefiniowaqć ten rekord tak by rozróżniany był ten fakt. Zapiszmy:

Przykład.

      Osoba=record
         Nazwisko, Imie    : string;
         DataUrodzenia: Data;
         StanCywilny    : (wolny,zonaty,owdowialy,rozwiedziony);
         case plec:(mezczyzna,kobieta) of
           mezczyzna: (waga: real;
                       brodaty: boolean);
           kobieta:   (wymiary: array[1..3] of real)
      end;
Operacje na wariantach najlepiej jest pogrupować w instrukcję wybiórczą (case), której struktura odzwierciedla strukturę rekordu z wariantami.
case x.sn of
   c1: s1;
   c2: s2;
   ...
   cm: sm
end;
Podam teraz przykład obliczania odległości na płaszczyźnie przy zadanych kartezjańskich lub biegunowych współrzędnych punktów.

Przykład.

(*  
    podprogram OdlAB oblicza odległość między dwoma punktami
    A i B zadanymi w postaci zmiennych a i b typu rekordowego
    Wspolrzedne, będącego typem rekordowym z wariantami
    (patrz: Iglewski,...)
*)
function OdlAB(a, b: Wspolrzedne): real;
var d: real;
begin
 case a.rodzaj of
  kartezjanskie: case b.rodzaj of
     kartezjanskie: d:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
     biegunowe    : d:=sqrt(sqr(a.x-b.r*cos(b.fi))+sqr(a.y-b.r*sin(b.fi))
     end
  biegunowe: case b.rodzaj of
     kartezjanskie: d:=sqrt(sqr(b.x-a.r*cos(a.fi))+sqr(b.y-a.r*sin(a.fi));
     biegunowe    : d:=sqrt(sqr(a.r)+sqr(b.r)-2*a.r*b.r*cos(a.fi-b.fi))
     end;
 OdlAB:=d;
end;
Następny przykład został wzięty z podręcznika Turbo Pascal 7, Language Guide, str. 33.

Przykład.

TWielobok=record
   X, Y : Real;
case Rodzaj : Figura of
   TProstokat: (Wysokosc,Szerokosc: real);
   TTrojkat:   (bok1,bok2,kat: real);
   TOkrag:     (promien: real)
end;

Stałe typu rekordowego

stała rekordowa
|
+-->(  (  )--->[ Nazwa pola ]--->(  :  )---[ stała określonego ]-->(  )  )-->
            |                                       typu           |
            +----------------(  ;  )<------------------------------+

Przykład.

const a: integer=3;
type  TPunkt=record X,Y: real end;
      TWektor=array[0..1] of TPunkt;
      TMiesiac=(Sty,Lut,Mar,Kwi,Maj,Cze,Lip,Sie,Wrz,Paz,Lis,Gru);
      TData=record D:1..31; M: TMiesiac; R: 1900..1999 end;
const Poczatek: TPunkt=(X: 0.0, Y: 0.0);
      Linia: TWektor=((X:-3.1; Y:1.5), (X:5.8; Y:3.0));
      Dzien: TData=(D:2; M:Gru; R:1998);
Pola musimy podawać w takim porządku w jakim pojawiły się w definicji typu rekordowego. Jeśli rekord zawiera pola typu plikowego to stałe tego typu nie mogą być definiowane. Jeśli rekord posiada warianty, to tylko pola wybranego wariantu można ustalić. W przypadku gdy wariant zawiera pole wyróżnika musimy to pole wyspecyfikować.

File translated from TEX by TTH, version 4.03.
On 16 Oct 2013, 21:50.