Difference between revisions of "Generics/ru"
Line 11: | Line 11: | ||
Обе [библиотеки], '''FGL''' и rtl-generics могут использоваться в обоих режимах. | Обе [библиотеки], '''FGL''' и rtl-generics могут использоваться в обоих режимах. | ||
− | ==fgl | + | ==Модуль fgl== |
− | + | Самый простой способ начать работу с дженериками - это использовать [http://freepascal.org/docs-html/current/rtl/fgl/index.html fgl unit], который является модулем-прототипом для классов дженериков базовой системы. Пока он содержит несколько основных классов: | |
* TFPGList | * TFPGList | ||
* TFPGObjectList | * TFPGObjectList | ||
Line 18: | Line 18: | ||
* TFPGMap | * TFPGMap | ||
− | === | + | ===Как начать=== |
− | + | В следующем простом примере показано, как хранить несколько экземпляров определенного пользователем класса в списке: | |
<syntaxhighlight> | <syntaxhighlight> | ||
Line 37: | Line 37: | ||
begin | begin | ||
− | // | + | // создаем список и добавляем элемент |
list := TMyList.Create; | list := TMyList.Create; | ||
c := TMyClass.Create; | c := TMyClass.Create; | ||
c.fld1 := 'c1'; | c.fld1 := 'c1'; | ||
list.Add(c); | list.Add(c); | ||
− | // | + | // получаем элемент из списка |
c := list[0]; | c := list[0]; | ||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 21:35, 26 December 2018
│
English (en) │
français (fr) │
한국어 (ko) │
polski (pl) │
русский (ru) │
Вступление
FPC имеет официальную поддержку дженериков в синтаксисе Objfpc начиная с версии 2.2. и Delphi-совместимый синтаксис начиная с версии 2.6.0.
Дженерики иногда называют параметризованными типами.
Причина, по которой FPC поддерживает два разных диалекта, Objfpc и Delphi, заключается в том, что у FPC были дженерики до Delphi.
Можно использовать модули, написанные в синтаксисе Objfpc, в других модулях, использующих синтаксис Delphi, и наоборот.
Free Generics Library или FGL является нативной реализацией class templates, написанной в обобщенном синтаксисе Objfpc.
Rtl-generics package является реализацией class templates, написанной в синтаксисе дженериков Delphi, и пытается быть совместимым с библиотекой дженериков Delphi. Этот пакет является стандартным в FPC 3.1.1.+, но есть версия, доступная для FPC 3.0.4.
Обе [библиотеки], FGL и rtl-generics могут использоваться в обоих режимах.
Модуль fgl
Самый простой способ начать работу с дженериками - это использовать fgl unit, который является модулем-прототипом для классов дженериков базовой системы. Пока он содержит несколько основных классов:
- TFPGList
- TFPGObjectList
- TFPGInterfacedObjectList
- TFPGMap
Как начать
В следующем простом примере показано, как хранить несколько экземпляров определенного пользователем класса в списке:
{$mode objfpc}
uses fgl;
type
TMyClass = class(TObject)
fld1 : string;
end;
TMyList = specialize TFPGObjectList<TMyClass>;
var
list : TMyList;
c : TMyClass;
begin
// создаем список и добавляем элемент
list := TMyList.Create;
c := TMyClass.Create;
c.fld1 := 'c1';
list.Add(c);
// получаем элемент из списка
c := list[0];
Custom Generic Classes
If the generics defined in the fgl unit do not suit your needs, you may need to define your own generic classes from scratch using the underlying language primitives.
A generic class is defined using the keyword generic before the class name and use in class declaration:
type
generic TList<T> = class
Items: array of T;
procedure Add(Value: T);
end;
Example of generic class implementation:
implementation
procedure TList.Add(Value: T);
begin
SetLength(Items, Length(Items) + 1);
Items[Length(Items) - 1] := Value;
end;
A generic class can be simply specialized for a particular type by using the specialize keyword.
Type
TIntegerList = specialize TList<Integer>;
TPointerList = specialize TList<Pointer>;
TStringList = specialize TList<string>;
Other Points
- The compiler parses a generic, but instead of generating code it stores all tokens in a token buffer inside the PPU file.
- The compiler parses a specialization; for this it loads the token buffer from the PPU file and parses that again. It replaces the generic parameters (in most examples "T") by the particular given type (e.g. LongInt, TObject).
The code basically appears as if the same class had been written as the generic but with T replaced by the given type.
Therefore in theory there should be no speed differences between a "normal" class and a generic one.
Example
An example of how to use generics to write a function gmax()
that takes the maximum of two not-yet-typed variables. Note that while the functions here are namespaced by the classname, FPC versions from 3.1.1 onwards also support fully free-standing generic methods.
program UseGenerics;
{$mode objfpc}{$H+}
type
generic TFakeClass<_GT> = class
class function gmax(a,b: _GT):_GT;
end;
TFakeClassInt = specialize TFakeClass<integer>;
TFakeClassDouble = specialize TFakeClass<double>;
class function TFakeClass.gmax(a,b: _GT):_GT;
begin
if a > b then
result := a
else
result := b;
end;
begin
// show max of two integers
writeln( 'Integer GMax:', TFakeClassInt.gmax( 23, 56 ) );
// show max of two doubles
writeln( 'Double GMax:', TFakeClassDouble.gmax( 23.89, 56.5) );
readln();
end.