Функции, как и процедуры, предназначены для размещения дополнительных блоков внутри основной программы. Единственное отличие функции от процедуры в том, что она всегда должна возвращать вызвавшей ее программе какое-то значение (результат своих действий). Синтаксис написания функции почти аналогичен синтаксису процедуры. Исключение составляет заголовок функции, который должен начинаться с ключевого слова function и заканчиваться типом возвращаемого значения.
function имя_процедуры (список_параметров) : тип результата; директивы;
[локальные_объявления]
begin
<операторы> end;
®В каждой из функций Delphi автоматически создается идентификатор Result, имеющий тот же тип, что и возвращаемое функцией значение. Этому идентификатору и присваивается возвращаемое функцией значение.
Вспомним предыдущий пример с расчетом площади прямоугольника и представим его в виде функции.
function SquareRectangle(X,Y : integer):integer; begin
Result:=X*Y; end;
Для вызова функции из основной программы также необходимо указать ее имя и при необходимости список ее параметров.
var Square:integer;
Square := SquareRectangle(100, 200);
{переменной Square присвоено значение, возвращаемое функцией SquareRectangle}
Особенности объявления и передачи параметров
В процедурах и функциях Delphi различают четыре основных типа параметров:
• Значения.
• Константы; параметр передается в виде константы и объявляется при помощи ключевого слова const.
• Переменные; параметр объявляется при помощи ключевого слова var.
• Выходные параметры; объявляются при помощи ключевого слова out.
С использованием в роли параметров обычных значений мы уже знакомы из предыдущего материала. Такой способ применяется наиболее часто. Однако при этом вы должны знать, что следующим шагом, позволяющим компилятору Delphi еще лучше оптимизировать код приложения, будет применение константы вместо обычного параметра-значения. Единственным условием определения параметра в виде константы должна быть 100-процентная уверенность в том, что в теле функции этот аргумент не будет претерпевать каких-либо изменений. Вот пример метода из модуля SysUtils:
function DateToStr(const DateTime: TDateTime): string; begin
DateTimeToString(Result, ShortDateFormat, DateTime); end;
Задача функции - преобразовать в текстовый вид значения даты/времени. Обратите внимание, что в теле функции аргумент DateTime не подвергается никаким модификациям, а это значит, что его целесообразно объявить в виде константы.
Как быть, если результат функции невозможно представить одним-единст-венным значением? Допустим, возникла необходимость одновременно вычислять не только площадь, но и периметр прямоугольника. Есть несколько вариантов решения этой проблемы. Первый вариант находится на поверхности - мы объявляем две специализированные функции. Первая функция вычисляет площадь, а вторая - периметр. Этот вариант достаточно прост, и мы его не рассматриваем.
Второй вариант более оригинален. Мы объявляем тип TMyRec. Это запись с двумя полями, предназначенными для хранения значений площади и периметра.
uses SysUtils, Classes,
type
TMyRec = record
Square, Perimeter : REAL; end;
А теперь описываем функцию, результатом которой будет данная запись
TmyRec:
function MyFunction(SideA, SideB : Real):TMyRec; begin
Result.Square:=SideA*SideB; Result.Perimeter:=2*(SideA+SideB); end;
На мой взгляд, это весьма элегантное решение нашей задачки: для получения площади и периметра достаточно однократно вызвать функцию MyFunction.
Однако благодаря высокой гибкости языка программирования Delphi, возможные варианты решения поставленной задачи на этом не исчерпываются. Третий способ заключается во включении переменной в перечень параметров функции. Такой способ передачи параметра будем называть передачей параметра по ссылке.
function MyFunction(SideA, SideB : Real; var Perimeter : Real) : Real; begin
Result:=SideA*SideB;
Perimeter:=2*(SideA+SideB);
end;
Площадь прямоугольника мы по привычке возвращаем во внутренний идентификатор Result, а значение периметра присваиваем формальному параметру Perimeter. А дальше вашему вниманию предлагается несколько строк кода, демонстрирующих способ вызова данной функции.
var Square, Perimeter : Real; begin
Square:=MyFunction(5, 10, Perimeter);
WriteLn(Square);
WriteLn(Perimeter);
ReadLn;
end;
Мы объявили две переменные вещественного типа. В переменную Square (предназначенную для хранения площади) результат вычислений помещается уже привычным для нас способом. А переменная, в которую мы намереваемся поместить периметр прямоугольника, передается как формальный параметр. После выполнения функции результат вычислений выводится на экран.
Передача параметра по ссылке пригодится не только для возврата результатов выполнения метода. Параметр-переменная пригодится и для передачи в процедуру какого-то значения. Однако в Delphi есть способ объявления параметров, специализирующихся только на возврате значений. Для их объ-
явления применяют ключевое слово out. Наиболее часто этот тип аргументов применяется при работе с технологиями COM и COBRA.
function Supports(const Instance: Ilnterface; const IID: TGUID; out Intf): Boolean; begin
Result := (Instance <> nil) and (Instance.QueryInterface(IID, Intf) = 0); end;
При определении нетипизированного параметра его имени обязательно должно предшествовать одно из ключевых слов: var, const или out.
Еще одним достоинством языка Object Pascal является возможность передачи в процедуры и функции в качестве параметра массива или даже открытого массива. Посмотрите на пример объявления функции ArraySum() в программе OpenArrayDemo.
program OpenArrayDemo;
{$APPTYPE CONSOLE}
uses SysUtils;
function ArraySum(Param : Array of Integer):integer;
var I : Integer;
begin
Result:=0;
for I:=Low(Param) to High(Param) do Result:=Result+Param[i]; end;
var Sum : Integer; begin
Sum:=ArraySum([1,2,3]);
WriteLn(Sum);
ReadLn;
end.
При острой необходимости Delphi позволяет программисту не типизировать параметр.
procedure AssignFile( var F; FileName: string);
Предложенное объявление процедуры AssignFile позволяет в качестве аргумента передавать файл любого типа. В заголовке метода мы можем сразу задать параметру значение по умолчанию. Для этого после объявления типа параметра ставим знак равенства и значение аргумента:
function MyFunc(X:integer, Y:integer = 10):integer; begin
result :=X+Y; end;
Теперь при вызове объявленной таким образом функции из основной программы программисту предоставляется возможность оставить параметр по умолчанию прежним или передать через него новое значение:
var Z : integer;
Z := MyFunc(2, 20); //параметру Y передано значение 20 или
Z := MyFunc(2); //параметр Y принимает значение по умолчанию
ОПри описании функции параметры по умолчанию должны размещаться в конце списка. В противном случае Delphi откажется воспринимать функцию. Вот пример ошибки при определении аргумента по умолчанию:
function MyFunc(X:integer =10, Y:integer):integer; //код ошибочен