Delphi 2009 - změny v kompilátoru a RTL (část 2) - generika

vložil Radek Červinka 31. prosince 2009 02:50

Delphi 2009 přináší několik novinek kompilátoru a RTL z nichž nejzásadnější je podpora Unicode, Generika (generics), anonymní metody a pak zbytek.

Minule byla první část změn v Delphi 2009, nyní přicházejí na řadu generika - generics (dobré číst postupně od Delphi 2007).

Generika (generics) v Delphi 2009

Nejdříve raději příklad, kde se bude demonstrovat syntaxe a snad i použití:

    1program Project1;
    2
    3{$APPTYPE CONSOLE}
    4
    5uses
    6  SysUtils, TypInfo;
    7
    8type
    9  // deklarace generické třídy
   10  TSampleClass <T> = class
   11  private
   12    fdata: T;
   13  public
   14    function ReadT: T;
   15    procedure SetT (value: T);
   16  end;
   17
   18
   19// implementace dvou metod generické třídy
   20function TSampleClass<T>.ReadT: T;
   21begin
   22  exit (fData);  // novinka - rozsireni Exit o parametr
   23  // nebo treba  Result := fData;
   24end;
   25
   26procedure TSampleClass<T>.SetT(value: T);
   27begin
   28  fData := value;
   29end;
   30
   31var
   32  t1: TSampleClass<Integer>;  // data budou integer
   33  t2: TSampleClass<string>;  // data budou string
   34  s: string;
   35  i: integer;
   36begin
   37
   38  t1 := TSampleClass<Integer>.Create;
   39  t1.SetT (10);
   40
   41  t2 := TSampleClass<string>.Create;
   42  t2.SetT ('test');
   43
   44  // demonstrace typoveho přiřazení
   45  s := t2.ReadT;
   46  i := t1.ReadT;
   47
   48  writeln (s, i);  // vypise test10
   49  t2.Free;
   50  t1.Free;
   51end.

Snad je tedy z demo příkladu patrné o co jde, ale raději: TSampleClass je námi definovaná generická třída a podle deklarace pak obsahuje typ dat a umožňuje nám s nimi pracovat. Navíc nás kompilátor chrání aby nebylo provedeno neplatné přiřazení atd.

Je evidentní, že tomu něco schází, jelikož nelze dělat některé oprace nad obecnými daty. Naštěstí autoři na to myslí a přidávají tři nové (resp. dvě z nich jen rozšiřují stávající kód) možnosti:

  • Default (T) - novinka: vrací nulovou, nebo prázdnou hodnotu pro aktuální typ (tj. třeba 0 pro integer, '' pro string nebo třeba nil pro objekt)
  • SizeOf (T) - velikost v paměti, ale pro objekty a řetězce vrací velikost pointeru tedy 4
  • TypeInfo (T) - vrací informace RTTI o generickém typu (třeba GetTypeName (TypeInfo (T)) by nám vratilo 'Integer' a v druhém případě 'string'
    1function TSampleClass<T>.Info: string;
    2begin
    3  Result := GetTypeName (TypeInfo (T));
    4end;
    5
    6writeln(t1.Info);

Takže to je deklarace obecného generického typu. Je patrné, že to stále není úplně ono. Proto Object Pascal umožňuje deklaraci rozšířit o limit (Class Constraints), tj. jakého typu musí být nejméně parametr generického typu. Špatně se to vysvětluje tak raději příklad:

Změníme deklaraci z předchozího příkladu na

    1type
    2  TSampleClass <T: class> = class

Nyní při kompilaci kompilátor zaprotestuje na t1: TSampleClass<Integer> jelikož Integer není třída (samozřejmě i na druhé deklaraci).

Výhodou je, že nyní máme zaručeno, že data budou určitě třída, tj. můžeme volat metody z TObject, např. novou metodu ToString (fData.ToString - viz minule).

Samozřejmě můžeme specifikovat omezení na libovolnou třídu a pak můžeme volat metody té třídy.

Default constructor

Teď by kompilátor vždy pro třídu volal TObject.Create, ale existuje možnost jak tomu zamezit.

    1type
    2  TConstrClass <T: class, constructor> = class
    3  private
    4    val: T;
    5  public
    6    constructor Create;
    7    function Get: T;
    8  end;

Nyní můžeme napsat

    1constructor TConstrClass<T>.Create;
    2begin
    3  val := T.Create;
    4end;

a kompilátor bude volat vždy správný constructor.

Předdefinované generické typy

Pro usnadnění práce existuje několik předdefinovaných často používaných typů deklarovaných v unitu Generics.Collections.

    1type
    2  TList<T> = class
    3  TQueue<T> = class
    4  TStack<T> = class
    5  TDictionary<TKey,TValue> = class
    6  
    7  a pak
    8  
    9  TObjectList<T: class> = class(TList<T>)
   10  TObjectQueue<T: class> = class(TQueue<T>)
   11  TObjectStack<T: class> = class(TStack<T>)

např. tedy

    1var
    2  t1: TList<Integer>;
    3begin
    4
    5  t1 := TList<Integer>.Create;
    6  t1.Add(10);
    7
    8  t1.Free;

Výhodou takového kódu je větší robustnost napsaného kódu, kdy kompilátor kontroluje co může.

Předdefinované rozhraní

Jen pro úplnost: v unitu Generics.Default jsou definovány některé rozhraní, z nichž důležité jsou

  • IComparer<T>
  • IEqualityComparer<T>

a z nich vycházející TComparer<T> a další. Používají se např. při řazení seznamů.

Téma je rozsáhlejší, ale jako úvod by to snad mohlo stačit.


Nabízíme Delphi školení a konzultace na různá témata, primárně ve Vaší firmě.

Tagy: , , ,

Jazyk | Recenze

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS