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í:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, TypInfo;

type
  // deklarace generické třídy
  TSampleClass <T> = class
  private
    fdata: T;
  public
    function ReadT: T;
    procedure SetT (value: T);
  end;


// implementace dvou metod generické třídy
function TSampleClass<T>.ReadT: T;
begin
  exit (fData);  // novinka - rozsireni Exit o parametr
  // nebo treba  Result := fData;
end;

procedure TSampleClass<T>.SetT(value: T);
begin
  fData := value;
end;

var
  t1: TSampleClass<Integer>;  // data budou integer
  t2: TSampleClass<string>;  // data budou string
  s: string;
  i: integer;
begin

  t1 := TSampleClass<Integer>.Create;
  t1.SetT (10);

  t2 := TSampleClass<string>.Create;
  t2.SetT ('test');

  // demonstrace typoveho přiřazení
  s := t2.ReadT;
  i := t1.ReadT;

  writeln (s, i);  // vypise test10
  t2.Free;
  t1.Free;
end.

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'
function TSampleClass<T>.Info: string;
begin
  Result := GetTypeName (TypeInfo (T));
end;

writeln(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

type
  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.

type
  TConstrClass <T: class, constructor> = class
  private
    val: T;
  public
    constructor Create;
    function Get: T;
  end;

Nyní můžeme napsat

constructor TConstrClass<T>.Create;
begin
  val := T.Create;
end;

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.

type
  TList<T> = class
  TQueue<T> = class
  TStack<T> = class
  TDictionary<TKey,TValue> = class
  
  a pak
  
  TObjectList<T: class> = class(TList<T>)
  TObjectQueue<T: class> = class(TQueue<T>)
  TObjectStack<T: class> = class(TStack<T>)

např. tedy

var
  t1: TList<Integer>;
begin

  t1 := TList<Integer>.Create;
  t1.Add(10);

  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.

Tagy: , , ,

Jazyk | Recenze

Komentování ukončeno

Naše nabídka

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).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

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.

Poslední komentáře

Comment RSS

Dle měsíců