PascalABC.NET

Обобщенные подпрограммы: обзор

Обобщенной подпрограммой (generic) называется подпрограмма, параметризованная одним или несколькими типами. Подпрограмма образуется из обобщенной подпрограммы подстановкой конкретных типов в качестве параметров. Параметры указываются после имени подпрограммы в угловых скобках.

Например, следующая  обобщённая функция параметризована одним параметром:

function FindFirstInArray<T>(a: array of T; val: T): integer;
begin
  Result := -1;
  for var i:=0 to a.Length-1 do
    if a[i]=val then
    begin
      Result := i;
      exit;
    end;
end;

var x: array of string;

begin
  SetLength(x,4);
  x[0] := 'Ваня';
  x[1] := 'Коля';
  x[2] := 'Сережа';
  x[3] := 'Саша';
  writeln(FindFirstInArray(x,'Сережа'));
end.

При вызове обобщенной подпрограммы тип-параметр обобщения можно не указывать, поскольку компилятор выводит типы параметров шаблона по типам фактических параметров. В данном случае после выведения получено: T=string.

При выведении требуется точное соответствие типов, приведение типов не допускается. Например, при компиляции следующего кода

...
var
x: array of real;

begin
  SetLength(x,3);
  x[0] := 1;
  x[1] := 2.71;
  x[2] := 3.14;
  writeln(FindFirstInArray(x,1));
end.

произойдет ошибка. Причина состоит в том, что первый параметр имеет тип array of real, а второй - тип integer, что не соответствует ни одному типу T в заголовке обобщенной функции. Для решения проблемы следует либо изменить тип второго параметра на real:

FindFirstInArray(x,1.0)

либо явно после имени функции в угловых скобках указать имя типа, которым параметризован данный вызов:

FindFirstInArray&<real>(x,1)

Использование знака & здесь обязательно, поскольку в противном случае компилятор трактует знак < как "меньше".

Обобщёнными могут быть не только обычные подпрограммы, но и методы классов, а также методы другого обобщённого класса. Например:

type
  Pair<T,Q> = class
    first: T;
    second: Q;
    function ChangeSecond<S>(newval: S): Pair<T, S>;
  end;

function Pair<T,Q>.ChangeSecond<S>(newval: S): Pair<T,S>;
begin
  result := new Pair<T,S>;
  result.first := first;
  result.second := newval;
end;

var
  x: Pair<integer,real>;
  y: Pair<integer,string>;
begin

  x := new Pair<integer,real>;
  x.first := 3;
  y := x.ChangeSecond('abc');
  writeln(y.first, y.second);
end.

По окончании работы данная программа выведет 3abc.