Вероятно, проще понять это на примере. Для начала, напишем процедуру, которая меняет местами два значеня типа Integer:
-- Это описание (спецификация): procedure Swap(Left, Right : in out Integer); -- ..а это тело: procedure Swap(Left, Right : in out Integer) is Temporary : Integer; begin Temporary := Left; Left := Right; Right := Temporary; end Swap;
Процедура Swap хороша, но слишком ограничена. Мы не можем использовать Swap для того, чтобы менять местами величины типа Float, Unbounded_String или какие-либо другие. Более обобщенная версия подпрограммы Swap, причем такая, чтобы было возможно заменить тип Integer настраиваемым типом - это как раз то, что нам необходимо. Настраиваемая версия Swap будет выглядеть следующим образом:
-- Это описание (спецификация): generic type Element_Type is private; procedure Generic_Swap(Left, Right : in out Element_Type); -- .. а это тело: procedure Generic_Swap(Left, Right : in out Element_Type) is Temporary : Element_Type; begin Temporary := Left; Left := Right; Right := Temporary; end Generic_Swap;
В общем случае, для того, чтобы создать настраиваемую версию подпрограммы (или пакета), необходимо написать подпрограмму с использованием нескольких настраиваемых типов. Затем, перед подпрограммой или пакетом написать ключевое слово ``generic'' и список того, что необходимо сделать настраиваемым. Этот список называют формальными параметрами настройки; он похож на список параметров в описании процедуры. Cмысл фразы ``is private'' будет пояснен ниже.
Для использования настраиваемой подпрограммы (или пакета) необходимо создать реальную подпрограмму (или пакет) из настраиваемой. Этот процесс называется конкретизацией, а результат называется конкретизированным модулем или экземпляром модуля. Это, конечно, слишком громкие термины для такой простой концепции. Например, вот каким образом можно создать три экземпляра процедуры Swap из настраиваемой процедуры:
procedure Swap is new Generic_Swap(Integer); procedure Swap is new Generic_Swap(Float); procedure Swap is new Generic_Swap(Unbounded_String);
Заметим, что при конкретизации настраиваемого модуля парамеры ему нужно передавать точно так же, как и при обыкновенном вызове подпрограммы.
После этого можно вызывать процедуру Swap, которая принимает в качестве параметров переменные типа Integer, Float и Unbounded_String. Таким образом, если и A и B являются переменными типа Integer, Swap(A,B) поменяет их местами. Точно также, как и для любой из подпрограмм, имеющих одинаковые имена, Ada во время компиляции определит какую из них вызывать, в зависимости от типов аргументов.
Ниже приведена простая тестовая программа для процедуры Generic_Swap:
with Generic_Swap; procedure Tswap is procedure Swap is new Generic_Swap(Integer); A, B : Integer; begin A := 5; B := 7; Swap(A, B); -- Теперь A=7, а B=5. end Tswap;
Для простоты мы показали конкретизацию процедуры Swap внутри процедуры Tswap, хотя в реальных программах почти все группируется в пакет, и тогда конкретизации будут находиться внутри его тела.
К этому разделу упражнение отсутствует.
Вы можете перейти к следующему разделу.
Вернуться к предыдущему разделу | Вернуться к содержанию Урока 11 |
---|
David A. Wheeler (dwheeler@ida.org)
Исходная копия этого документа находится по адресу
"http://www.adahome.com/Tutorials/Lovelace/s11s1.htm".
Исходная копия перевода размещена на сайте http://www.ada-ru.org
Перевод: Юрий Королев
Общая редакция перевода: Г.Ю. Сисюк