Difference between revisions of "Generics/ru"
Line 88: | Line 88: | ||
== Примеры == | == Примеры == | ||
− | {{: | + | Пример использования дженериков для написания функции gmax(), которая принимает максимум две еще-не-типизированные переменные. |
+ | Обратите внимание, что функции имеют пространство имен по имени класса. Недостатком может быть то, что дженерики не могут быть перегружены. | ||
+ | |||
+ | <syntaxhighlight> | ||
+ | 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 | ||
+ | // показать большее из двух целых [чисел] | ||
+ | writeln( 'Integer GMax:', TFakeClassInt.gmax( 23, 56 ) ); | ||
+ | // показать большее из двух [чисел] с плавающей точкой | ||
+ | writeln( 'Double GMax:', TFakeClassDouble.gmax( 23.89, 56.5) ); | ||
+ | readln(); | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
==См. также== | ==См. также== |
Revision as of 22:38, 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];
Пользовательские классы дженериков
Если дженерики, определенные в модуле fgl, не соответствуют вашим потребностям, вам может потребоваться определить свои собственные классы дженериков с нуля, используя базовые языковые примитивы.
Класс-дженерик определяется с помощью keyword (ключевого слова) generic перед именем класса и используется в объявлении класса:
type
generic TList<T> = class
Items: array of T;
procedure Add(Value: T);
end;
Пример реализации класса-дженерика:
implementation
procedure TList.Add(Value: T);
begin
SetLength(Items, Length(Items) + 1);
Items[Length(Items) - 1] := Value;
end;
Класс-дженерик может быть просто специализирован для определенного типа с помощью ключевого слова specialize.
Type
TIntegerList = specialize TList<Integer>;
TPointerList = specialize TList<Pointer>;
TStringList = specialize TList<string>;
Другие пункты
- Компилятор анализирует общий тип, но вместо генерации кода он сохраняет все токены в буфере токенов внутри файла PPU.
- Компилятор разбирает специализацию; для этого он загружает буфер токенов из файла PPU и анализирует его снова. Он заменяет общие параметры (в большинстве примеров "T") конкретным заданным типом (например, LongInt, TObject).
Код в основном выглядит так, как будто тот же класс был написан как общий, но с заменой T на данный тип.
Поэтому в теории не должно быть различий в скорости между «нормальным» классом и классом-дженериком.
Примеры
Пример использования дженериков для написания функции gmax(), которая принимает максимум две еще-не-типизированные переменные. Обратите внимание, что функции имеют пространство имен по имени класса. Недостатком может быть то, что дженерики не могут быть перегружены.
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
// показать большее из двух целых [чисел]
writeln( 'Integer GMax:', TFakeClassInt.gmax( 23, 56 ) );
// показать большее из двух [чисел] с плавающей точкой
writeln( 'Double GMax:', TFakeClassDouble.gmax( 23.89, 56.5) );
readln();
end.