При выведении требуется точное соответствие типов, приведение типов не допускается. Например, при компиляции следующего кода
...
varx: array ofreal;
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&(x,1)
Использование знака & здесь обязательно, поскольку в противном случае компилятор трактует знак < как <���меньше<.
Обобщёнными могут быть не только обычные подпрограммы, но и методы классов, а также методы другого обобщённого класса. Например:
type
Pair = class
first: T;
second: Q;
functionChangeSecond(newval: S): Pair;
end;
functionPair.ChangeSecond(newval: S): Pair;
begin
result := newPair;
result.first := first;
result.second := newval;
end;
var
x: Pair;
y: Pair;
begin
x := newPair;
x.first := 3;
y := x.ChangeSecond('abc');
writeln(y.first, y.second);
end.
По окончании работы данная программа выведет 3abc.
Обобщенные подпрограммы в качестве параметров
Обобщенная подпрограмма может выступать в качестве формального параметра другой обобщенной подпрограммы.
Например, в классе System.Array имеется несколько статических обобщенных методов с обобщенными подпрограммами в качестве параметров. Так, System.Array.Find имеет следующий прототип:
System.Array.FindAll(a: array ofT; pred: Predicate): array ofT;
и возвращает подмассив массива a элементов T, удовлетворяющих условию pred.
Приведем пример вызова этой функции:
functionf(x: integer): boolean;
begin
Result := ;
end;
vara := Seq(1,3,6,5,8);
varb := System.Array.FindAll(a,x -> x mod2 = 0);
Здесь возвращается массив b, содержащий все четные значения массива a в том же порядке.
Ограничения на параметры обобщенных подпрограмм и классов
По умолчанию с переменными, имеющими тип параметра обобщенного класса или подпрограммы, внутри методов обобщённых классов и обобщенных подпрограмм можно делать лишь ограниченный набор действий: присваивать и сравнивать на равенство (отметим, что в NET сравнение на равенство внутри обобщений запрещено!).
Например, данный код будет работать:
functionEq(a,b: T): boolean;
begin
Result := a = b;
end;
Можно также использовать присваивание переменной, имеющей тип параметра обобщенного класса или подпрограммы, значение по умолчанию, используя конструкцию default(T) - значение по умолчанию для типа T (nil для ссылочных типов и нулевое значение для размерных типов):
procedureDef( vara: T);
begin
a := default(T);
end;
Однако, данный код
functionSum(a,b: T): T;
begin
Result := a + b;
end;
вызовет ошибку компиляции до инстанцирования (создания экземпляра с конкретным типом). Такое поведение в .NET кардинально отличается от шаблонов в C++, где в коде шаблона можно использовать любые операции с шаблонными параметрами, и ошибка может произойти только в момент инстанцирования с конкретным типом.
Чтобы разрешить использование некоторых действий с переменными, имеющими тип параметра обобщенного класса или подпрограммы, используются ограничения на обобщенные параметры, задаваемые в секции whereпосле заголовка подпрограммы или класса:
type
MyPair = class
whereT: System.ICloneable;
private
x,y: T;
public
constructor(x,y: T);
begin
Self.x := x;
Self.y := y;
end;
functionClone: MyPair;
begin
Result := new MyPair(x.Clone,y.Clone);
end;
end;
В секции whereчерез запятую перечисляются следующие ограничения:
На 1 месте: слово classили слово recordили имя класса-предка.
На 2 месте: список реализуемых интерфейсов через запятую.
На 3 месте: слово constructor, указывающее, что данный тип должен иметь конструктор по умолчанию.
При этом каждое из мест, кроме одного, может быть пустым.
Для каждого типа-параметра может быть своя секция where, каждая секция where завершается точкой с запятой.
Пример.Обобщенная функция поиска минимального элемента в массиве. Элементы должны реализовывать интерфейс IComparable.
Читать дальше