Тема 13: Функції. Бібліотеки та модулі.

Функції

Функції є такими ж подпрограммами, як і процедури, з однією різницею: вони повертають значення зазначеного типу. Функція починається з ключового слова function і має наступний синтаксис:

 

function <ім'я функції> (<список параметрів>): <тип значення>;

const

   <Оголошення констант>;

type

   <Оголошення нових типів>;

var

   <Оголошення змінних>;

<Опис вкладених процедур і функцій>;

begin

  <Тіло процедури>;

end;

    

У тілі функції повинен бути оператор, який надає значення, що повертається стандартної змінної Result, що і призводить до повернення функцією значення. Result оголошувати не потрібно, він вже є в кожної функції. Зрозуміло, в Result потрібно присвоювати значення тільки вказаного в заголовку типу. приклад:

 

function MyFunc (i: integer): integer;

begin

   Result: = i * 2;

end;

    

Тут функція MyFunc приймає як параметр якесь ціле число, подвоює його і привласнює результат змінної Result. Це призводить до того, що функція повертає цей результат. Тепер ми можемо подвоїти ціле значення, викликавши цю функцію, наприклад:

 

myperem: = 5;

myperem: = MyFunc (myperem);

    

Що буде в результаті в змінної myperem? Якщо ви відповіли 10, то ви маєте рацію. Тут ми в першому кроці присвоюємо змінної цілого типу myperem значення 5. У другому кроці ми викликаємо функцію MyFunc, передаючи їй як параметр значення myperem. У третьому кроці ми присвоюємо отриманий від функції результат подвоєння знову в змінну myperem.

 

До речі, замість системної змінної Result можна використовувати ім'я функції:

 

function MyFunc (i: integer): integer;

begin

   MyFunc: = i * 2;

end;

    

Даний приклад дасть точно такий же результат. Який спосіб використовувати - справа вибору. Особисто я вважаю за краще використовувати Result, це виглядає якось більш стандартно. У будь-якому випадку, ви повинні знати про обидва способи.

 

На відміну від багатьох інших мов, в Lazarus змінної Result (або імені функції) значення можна привласнювати неодноразово, якщо цього вимагає логіка підпрограми. Наприклад, функція отримує два дійсних числа. Перше потрібно розділити на друге, і результат повернути. Але на нуль ділити не можна, тому щоб уникнути зависання програми, якщо друге число - нуль, то і повернути потрібно нуль. Таку функцію можна реалізувати наступним чином:

 

function Delenie (r1, r2: real): real;

begin

   if r2 = 0 then Result: = 0

   else Result: = r1 / r2;

end;

    

Добре, випробуємо функції на практиці. Нижче Button1 додайте Button2 з текстом в Caption:

 

Приклад подвоєння №2

    

Згенеруйте для другої кнопки подія OnClick, трохи вище цієї події опишіть функцію подвоєння FuncUdvoenie. В результаті у вас вийде наступне:

 

function FuncUdvoenie (st: string): string;

var

  r: real;

begin

   // отриманий рядок спочатку перетворимо в число:

   r: = StrToFloat (st);

   // тепер подвоїмо його:

   r: = r * 2;

   // тепер повернемо результат у вигляді рядка:

   Result: = FloatToStr (r);

end;

 

procedure TfMain.Button2Click (Sender: TObject);

begin

  ShowMessage (FuncUdvoenie (Edit1.Text));

end;

    

Зверніть увагу, тут ми пішли трохи іншим шляхом. Ми створили функцію, яка лише повертає результуючий число у вигляді рядка, а висновок цього рядка на екран організували при виконанні функції, в рядку

 

ShowMessage (FuncUdvoenie (Edit1.Text));

    

Тут в першому кроці ми викликаємо функцію FuncUdvoenie, передаючи їй як параметр текст з Edit1. У другому кроці відпрацьовує функція - перетворює цей текст в число, подвоює його, знову перетворює в рядок, і результат повертає компілятору. А в третьому кроці за допомогою функції ShowMessage () ми виводимо цей результат на екран. Реалізовано інакше, але працювати буде так само. Спробуйте. І поки не закривайте проект.

 

 

 

МОДУЛІ

Передумови виникнення модульного програмування Як відомого, програма – це алгоритм, записаний за допомогою мови програмування, тобто послідовність команд, виконання яких дозволяє одержати розв’язок деякої задачі. При розв’язанні складних задач застосовують так званий структурний підхід, суть якого полягає у тому, що складна задача розбивається на простіші підзадачі, до розв’язання яких зводиться початкова задача. Цей підхід реалізовується за допомогою технології процедурного програмування, яка передбачає розбиття основної задачі на підзадачі та оформлення останніх у вигляді підпрограм (процедур та функцій). Звичайно, технологія процедурного програмування значно спрощує розв’язання основної задачі, оскільки дає можливість зосереджуватися на розв’язанні кожної окремої підзадачі, як автономної одиниці. Окрім цього, підпрограми дозволяють частково розв’язувати проблему повторного використання розроблених програмних одиниць. Так один раз розробивши деяку підпрограму, її можна з легкістю використати при розробці іншої програми просто скопіювавши її текст. Але ж для цього ми завжди повинні пам’ятати у яких програмах які розроблено підпрограми. А також може скластися ситуація, коли нам необхідно копіювати десятки, а то й сотні підпрограм. Звичайно, об’єм такої програми буде значним, що значно ускладнює розробку програми. Зрозуміло, що в цьому випадку зручним був би механізм, який би дозволяв використовувати раніше створені підпрограми не копіюючи кожен раз текст ві дповідної підпрограми та не компілювати цю підпрограму кожного разу. Тобто доцільніше було б розробляти програму по частинам, а далі з’єднувати ці частини в єдине ціле – кінцеву програму. Саме ці проблеми і покликані розв’язувати модулі. Модуль – це автономно компілюємо програмна одиниця, яка може включати в себе опис констант, типів даних, змінних та підпрограм, які можуть бути використані в інших модулях та програмах. Саме завдяки автономності модулів та можливості їх багаторазового використання модулі набули широкого поширення при розробці програм.

Окрім проблем повторного використання коду, модулі часткового дозволяють розв’язувати проблеми організації даних. Використання модулів дозволяє “сховати” дані і процедури їх обробки всередині модуля , що дозволяє уникнути неправильного використання даних.

 

Структура модуля

Отже, модуль складається із заголовку і чотирьох складових частин, кожна з яких може бути порожньою.

Заголовок модуля складається із зарезервованого слова UNIT та імені Модуля UNIT <Ім’я модуля>; Ім’я модуля задається у формі ідентифікатора і повинно співпадати з іменем дискового файлу, в якому зберігається текст модуля .

 Так, наприклад, якщо маємо модуль, заголовок якого UNIT Vector; то текст відповідного модуля повинен зберігатися у однойменному  дисковому файлі з розширенням “Pas” (“Vector.pas”). При компіляції  створюється файл з розширенням “Dcu” (Global.Dcu). Саме це ім’я і

використовується для підключення модуля до основної програми або до іншого модуля. Робиться це в розділі описання модулів USES

USES Vector;

Описова частина відкривається зарезервованим словом INTERFACE. Тут містяться описання всіх глобальних об’єктів модуля (типів, констант, змінних та підпрограм), які повинні бути доступними основній програмі та/або іншим модулям, які підключають даний модуль. При описанні глобальних підпрограм в інтерфейсній частині вказується тільки їх заголовок.

INTERFACE

USES <Список модулів>;

CONST <Опис констант>;

TYPE <Опис типів користувача>;

VAR <Опис змінних>;

<Заголовки процедур і функцій>

Якщо тепер в основній частині програми в розділі описання модулів  підключити цей модуль USES Vector; то у програмі стануть доступними всі описані константи, типи, змінні та процедури і функції так, ніби вони були описані в самій основній програмі.