Но в Delphi есть и более элегантные средства для прерывания любых циклов - достаточно в нужном месте тела цикла записать слова breakили goto.
Слегка изменим последний пример:
repeat i:= i+1;
if i > 5 then break; until FALSE;
frmMain.lstProtokol.Items.add(inttostr(i));
Мы избавились от флага, и теперь при наступлении нужного нам события (i> 5) выполняется процедура break, и цикл заканчивается.
Действие процедуры breakв цикле whileрассмотрите самостоятельно, а цикл forпрерывается ещё проще:
for i:= 1 to 20 do begin if i > 5 then break;
end;
frmMain.lstProtokol.Items.add(inttostr(i));
Пример из школьной жизни. Нам нужно определить, под каким номером записан Ваня Ургант в классном журнале. Как учит нас Президент Медведев, вся документация должна вестись в электронном виде. Значит, классный журнал можно представить себе как массив, в котором записаны все ученики (числом 30 голов). Всё - начинаем перебирать массив:
for i:= 1 to 30 do begin
if name = ’Ваня Ургант’ then begin n:= i; break; end; end;
frmMain.lstProtokol.Items.add(inttostr(n));
Как только мы найдём в журнале нашего Ваню, дальше искать смысла нет - Ваня Ургант единственный и неповторимый! В переменной nпосле окончания цикла мы и найдём номер Вани в классном журнале. И хотя фамилия Вани начинается на букву «у», скорее всего это будет номер 1, ведь Ваня даже на Первом первый!
Можно привести и другие примеры - уже из спортивной жизни. Один удачный удар - нокаут, и бой между Николаем Валуевым и Ваней Ургантом преждевременно заканчивается. Такая же досада случилась и у хоккеистов сборной России по хоккею в матче с финнами, когда эти горячие парни забили нам шайбу в дополнительном периоде. Есть и более огорчительные для мужского достоинства примеры, но упоминать их было бы неспортивно!
Вместо breakвы можете использовать оператор goto, который передаёт управление какому-нибудь оператору за пределами цикла. Этот оператор должен быть обозначен меткой (иначе получится, как в сказке, пойди туда, не знаю куда!), которая должна быть объявлена в процедуре:
procedure _cycl; label vyhod;
var
i: integer; flag: boolean;
while TRUE do begin
i:= i + 1;
if i > 5 then goto vyhod;
end;
vyhod: frmMain.lstProtokol.Items.add(inttostr(i));
В данных примерах действие процедуры breakи оператора gotoодинаково - они просто передают управление следующему за циклом оператору, который печатает число выполненных итераций. Однако легко видеть, что оператор gotoгораздо более дальнобойный - он может передать управление любому оператору процедуры, которому предшествует метка (меток в процедуре может быть сколько угодно). Обычно применение операторов gotoв программе не приветствуется, поскольку они нарушают логику работы программы, перескакивая в произвольное место кода. Из этого следует, что ими не следует злоупотреблять, но в некоторых случаях они могут и облегчить понимание кода, если проверки выхода из цикла очень сложны. Обычно это бывает при выходе из вложенных циклов.
И последнее: при выходе из цикла с помощью gotoс программой ничего не случится, но никогда не запрыгивайте извне внутрь цикла!
Процедура exit
Процедура exitдействует более радикально - она досрочно завершает не только цикл, но и всю подпрограмму, в которой этот цикл находится.
Например, если при выполнении цикла whileсработала процедура exit,
while TRUE do begin i:= i + 1;
if i > 5 then exit;
end;
frmMain.lstProtokol.Items.add(inttostr(i));
end;
то число 6 в окне списка напечатано не будет, поскольку мы сразу же «улетим» в запроцедурное пространство. Такие «полные улёты» бывают полезны при выходе из вложенных циклов.
В последних версиях Delphiпроцедура exitможет возвращать значение того же типа, что и функция пользователя.
Так действует оператор returnв языках C# и C++.
Если функция exitне возвращает никакого значения, то ни круглые скобки, ни аргумент указывать не нужно.
Например, «по старинке» мы можем написать вот такую функцию GetRandom, которая возвращает случайное целое число в диапазоне iLo..iHi\
Function GetRandom(iLo, iHi: Integer): Integer;
begin
GetRandom := iLo + (Random (iHi - iLo + 1))
end;
Или
Function
GetRandom(iLo, iHi: Integer):
Integer;
begin
Result:= iLo + (Random (iHi - iLo +1))
end;
Эту же функцию мы можем обновить, возвращая случайное значение как аргумент функции exit:
Function GetRandom(iLo, iHi: Integer): Integer;
begin
exit(iLo + (Random (iHi - iLo + 1)));
end;
Естественно, в этой функции нет особого резона возвращать значение с помощью процедуры exit. Мы это сделали только для примера. Правильнее использовать процедуру exitименно для досрочного завершения функции.
Процедура continue
Процедура continue прерывает только текущую итерацию, и тело цикла выполняется с начала.
Продолжим терзать Ваню. Пусть вместе с ним в классе учатся Цекало, Светлаков, Мартиросян и другие лоботрясы, которые портят успеваемость. Подсчитаем число прилежных учеников в классе:
n:=0;
for i:= 1 to 30 do begin
if uspev = 2 then continue; n:= n+1; end;
frmMain.lstProtokol.Items.add(inttostr(n));
Как только мы наткнёмся на двоечника, сразу же переходим к следующему ученику, а троечников, хорошистов и отличников валим в одну кучу. Теперь классный руководитель точно знает, сколько билетов ему заказывать для поездки в Италию. Плюс ещё один билет - для Вани.
Более серьёзные и полезные примеры с процедурой continueвы найдёте дальше в этой книге.
Выводы
Используйте оператор for, когда число итераций известно заранее, а операторы whileи repeat- если не известно.
Если вы уверены, что цикл может быть выполнен хотя бы 1 раз, используйте repeat, в противном случае while.
Всегда следите, чтобы условие продолжения цикла неизбежно принимало такое значение, которое завершает цикл, иначе программа зациклится.
Для досрочного выхода из цикла пользуйтесь процедурами breakи exit, а также оператором goto.