Инструкции определяют алгоритмические действия внутри программы. Простые инструкции, такие как присваивание и вызовы процедур могут быть объединены в циклы, условные инструкции и другие структуры.
Составные инструкции внутри блоков и секциях initialization и finalization разделяются точками с запятой (;).
Простые инструкции
Простые инструкции не содержат в себе других инструкций. Простые инструкции – это присваивание, вызовы процедур и функций, переходы goto.
Инструкции присваивания
Инструкции присваивания имеет следующую форму:
Variable := expression
Где Variable – это ссылка на переменную, включая переменные, переменные с преобразованием типа, указатели или компоненты переменных структурированного типа.
Expression – любое выражение совместимое по присваиванию (внутри блока функции, переменная может быть заменена именем этой функции).
Символ ':=' иногда называют оператором присваивания. Оператор присваивания заменяет текущее значение переменной значением expression. Например:
I := 3;
Присваивает значение 3 переменной I. Переменная, указываемая в левой части выражения может присутствовать и в правой части. Например:
I := I + 1;
Увеличивает значение I. Кроме того, инструкции присваивания могут использоваться следующим образом:
X := Y + Z; Done := (I >= 1) and (I < 100); Hue1 := [Blue, Succ(C)]; I := Sqr(J) - I * K; Shortint(MyChar) := 122; TByteRec(W).Hi := 0; MyString[I] := 'A'; SomeArray[I + 1] := P^; TMyObject.SomeProperty := True;
Вызовы процедур и функций
Вызов процедуры состоит из имени процедуры (с указанием спецификатора или без такового), за которым следует список параметров (если требуется). Например:
PrintHeading; Transpose(A, N, M); Find(Smith, William); Writeln('Hello world!'); DoSomething(); Unit1.SomeProcedure; TMyObject.SomeMethod(X,Y);
При включении расширенного синтаксиса ({$X+}), вызовы функций могут обрабатываться так же как вызовы процедур:
MyFunction(X);
Когда вы вызываете функции таким образом, возвращаемые ими значения отбрасываются.
Инструкция Goto
Инструкция имеет форму:
goto label
и переносит выполнение программы на инструкцию, помеченную соответствующей меткой. Для установки такой отметки, необходимо сначала объявить метку. Затем вы должны предварить его меткой и двоеточием (:).
label: statementМетка объявляется следующим образом:
label label;Вы можете объявить сразу несколько меток:
label label1, ..., labeln;
Метка может быть любым допустимым идентификатором или числом от 0 до 9999. Объявление метки, помеченная инструкция и инструкция goto должны принадлежать одному блоку. То есть невозможно перейти в (или из) процедуру или функцию. Не помечайте одной меткой более одной инструкции. Например:
label StartHere; ... StartHere: Beep; goto StartHere;Создает бесконечный цикл, который вызывает процедуру Beep.
Кроме того, нет возможности перехода в (из) блоки try - finally или try -except. Инструкция goto часто не рекомендуется в структурном программировании. Однако, она иногда используется как способ выхода из вложенных циклов. Например:
procedure FindFirstAnswer; var X, Y, Z, Count: Integer; label FoundAnAnswer; begin Count := SomeConstant; for X := 1 to Count do for Y := 1 to Count do for Z := 1 to Count do if ... { some condition holds on X, Y, and Z } then goto FoundAnAnswer; ... { Code to execute if no answer is found } Exit; FoundAnAnswer: ... { Code to execute when an answer is found } end;
Обратите внимание, что мы используем goto для выхода из вложенного цикла. Никогда не используйте эту инструкцию для входа в цикл или структурированную инструкцию, поскольку это может привести к непредсказуемым поcледствиям.
Структурированные инструкции
Структурированные инструкции состоят из других инструкции. Применяйте структурированные инструкции, когда хотите выполнять прочие инструкции последовательно, условно или циклически.
Составные инструкции или инструкции with просто исполняют последовательность составных инструкции.
Условные инструкции if или case выполняют не более одной из своих инструкций в зависимости от указанного критерия.
Инструкции цикла repeat, while, и for выполняют последовательность своих вложенных инструкций циклически.
Особая группа инструкций, включающая конструкции raise, try...except и try...finally создает и обрабатывает исключительные ситуации.
Составные инструкции
Составные инструкции – это последовательность других инструкции (простых или составных), выполняемых в последовательности, в которой они следуют в программном коде. Составные инструкции обрамляются зарезервированными словами begin и end, а входящие в их состав простые инструкции разделяются точками с запятой (;). Например:
begin Z := X; X := Y; X := Y; end;
Последняя точка с запятой перед end необязательна. То есть этот пример может быть записан и так:
begin Z := X; X := Y; Y := Z end;
Составные инструкции необходимы в случаях, когда синтаксис Delphi требует одной инструкции. Кроме блоков в программах, функциях или процедурах, их можно встретить внутри других составных инструкций (условных или инструкциях циклов). Например:
begin I := SomeConstant; while I > 0 do begin ... I := I - 1; end; end;
Вы можете написать составную инструкцию, которая содержит единственный включенную инструкцию. Как и скобки в сложных выражениях begin и end иногда служат для того, чтобы упростить программный код и улучшить его читаемость. Вы также можете использовать пустые составные инструкции, которые не делают ничего:
begin end;
Инструкция With
Инструкция with это стенографический прием для обращения к полям записей или полям, свойствам или методам объектов. Синтаксис инструкции with:
with obj do statementили:
with obj1, ..., objn do statement
где obj это выражение, ссылающееся на объект, экземпляр объекта, экземпляр класса, интерфейса или экземпляр типа класса (метакласса).
statement - это любая простая или структурированная инструкция. Внутри statement вы можете обращаться к полям, свойствам и методам obj используя только их идентификаторы без спецификатора. Например:
type TDate = record Day: Integer; Month: Integer; Year: Integer; end; var OrderDate: TDate; //можно записать следующую инструкцию with: with OrderDate do if Month = 12 then begin Month := 1; Year := Year + 1; end else Month := Month + 1; // без инструкции with этот пример будет выглядеть: if OrderDate.Month = 12 then begin OrderDate.Month := 1; OrderDate.Year := OrderDate.Year + 1; end else OrderDate.Month := OrderDate.Month + 1;
Если интерпретация obj включает индексированние массива или переход по указателю, эти действия выполняются однократно перед выполнением инструкции. Это делает инструкцию with эффективной и экономичной. Это также обозначает, что присвоение значений переменных внутри инструкции не могут действовать на интерпретацию obj во время выполнения текущей инструкции with.
Каждое обращение к переменной или имени метода интерпретируется, если это возможно, как обращение к элементу указанного объекта или записи. Если существует другая переменная или метод с тем же именем, к которой вам необходимо получить доступ внутри инструкции with вам необходимо указать для нее спецификатор. Например:
with OrderDate do begin Year := Unit1.Year; ... end;
Когда в инструкции with, указывается несколько объектов или записей, вся конструкция интерпретируется как последовательность вложенных инструкций with. То есть:
with obj1, obj2, ..., objn do statementэквивалентно:
with obj1 do with obj2 do ... with objn do statement
В этом случае, каждое обращение к переменной или имени метода внутри инструкции интерпретируется, если возможно, как элемент objn, в противном случае, как элемент objn1; и так далее. То же самое правило применяется к интерпретации objs самих по себе. То есть, если, например, objn – это одновременно элемент obj1 и obj2, он интерпретируется как obj2.objn.
Поскольку для управления в инструкции with необходима переменная или поля, использование его для работы со свойствами, иногда может быть непростым. Инструкция with ожидает, что переменные, с которыми она обращается будут доступны по ссылке.
Основные моменты, которые необходимо учесть при использовании with:- Вы можете использовать with только для чтения значений свойств, помеченных только для чтения. Попытка изменить значение поля в записи или объекте, к которым обеспечивает доступ свойство, приводит к ошибке компиляции.
- Даже если свойство позволяет производить запись в поле, вы все равно не можете использовать инструкцию with для изменения значения этого поля.
Следующий пример иллюстрирует проблему применения инструкции with на свойствах, помеченных только для чтения и обеспечивающих доступ к записям. Предположим, у вас есть следующий класс:
TShape = class private FCenter: TPoint; public property Center: TPoint read FCenter; end;где TPoint это запись, которая объявлена следующим образом:
TPoint = record X, Y: Integer; end;
В общем случае свойство Center помечено как "только для чтения" и не позволяет изменять значение поля FCenter. В этом случае использование инструкции with приведет к ошибке компиляции. Center – это не переменная, и вы не можете ссылаться на нее:
with Shape.Center do begin X := 100; Y := 100; end;
Сложность также возникает при использовании with для свойств, разрешающих запись. Мы изменили объявление оригинального класса TShape, что бы разрешить запись в поле FCenter:
TShape = class private FCenter: TPoint; public property Center: TPoint read FCenter write FCenter; end;
Ошибка компиляции возникает даже в том случае, когда свойство Center разрешает запись. Для решения этой проблемы необходимо изменить программный код:
with Shape.Center do begin X := 100; Y := 100; end;следующим образом:
{ копируем значение Center в локальную переменную} TempPoint := Shape.Center; with TempPoint do begin X := 100; Y := 100; end; { восстанавливаем значение} Shape.Center := TempPoint;
Инструкции If
Существует две формы инструкции if: if...then и if...then...else.
синтаксис инструкции if...then:if expression then statement
где expression возвращает значение типа Boolean. Если expression возвращает значение True, выполняется инструкция statement. В противном случае этого не происходит. Пример:
if J <> 0 then Result := I / J;Синтаксис инструкции if...then...else:
if expression then statement1 else statement2
где expression возвращает значение типа Boolean. Если expression возвращает значение True, выполняется statement1, в противном случае, выполняется statement2. Например:
if J = 0 then Exit else Result := I / J;
Разделы then и else содержат по одной инструкции, которые могут быть структурированными. Например:
if J <> o then begin Result := I / J; Count := Count + 1; end else if Count = Last then Done := True else Exit;
Точка с запятой (;)между разделом then и ключевым словом else никогда не ставится. Вы можете поставить точку с запятой (;) после инструкции if , чтобы отделить ее от следующей инструкции в блоке, но разделы then и else требуют, чтобы между ними был только разделитель в виде пробела или символа возврата каретки. Вставка точки с запятой (;) перед else (в инструкции if) это распространенная ошибка при программировании.
Особые сложности возникают при соединении двух вложенных инструкций if. Это происходит потому, что одни инструкции if имеют раздел else, а другие – нет. При этом синтаксис обоих инструкций одинаков. В последовательности вложенных условных инструкций, где количество разделов else меньше, чем количество инструкций if, может быть непонятно, какой раздел else относится к какой инструкции if. Рассмотрим инструкцию вида:
if expression1 then if expression2 then statement1 else statement2;Оказывается, есть два способа разбора этого примера:
if expression1 then [if expression2 then statement1 else statement2];
if expression1 then [if expression2 then statement1 ] else statement2;
Компилятор, однако всегда разбирает такие случаи первым способом. То есть, в реальном программном коде инструкция:
if ... { expression1} then if ... {expression2} then ... {statement1} else ... {statement2}эквивалентна:
if ... {expression1} then begin if ... {expression2} then ... {statement1} else ... {statement2} end;
Правило такое: вложенные условные инструкции разбираются, начиная с последней вложенной инструкции, при этом каждый раздел else счязывается с ближайшей слева инструкцией if. Для того, чтобы заставить компилятор прочесть наш пример вторым способом, вам нужно записать его явно следующим образом:
if ... {expression1} then begin if ... {expression2} then ... {statement1} end end else ... {statement2};
Инструкции Case
Инструкции case может предоставить более удобную для чтения альтернативу инструкциям if с глубокой вложенностью. Инструкция case имеет вид:
case selectorExpression of caseList1: statement1; ... caseListn: statementn; end
где selectorExpression это любое выражение порядкового типа, меньшее, чем 32 бита (строковые типы и порядковые типы с размером более 32 бит не могут быть использованы). Каждый caseList может быть:
- числом, объявленной константой или выражением, которое компилятор может вычислить без запуска программы. Это может быть порядковый тип, совместимый с selectorExpression. Так 7, True, 4 + 5 * 3, 'A', и Integer('A') могут быть использованы как caseLists, но переменные и большая часть функций не могут. (исключение составляют некоторые встроенные функции вроде Hi и Lo.)
- Подмножеством, имеющим форму First..Last, где First и Last удовлетворяют указанным выше критериям и First is меньше, либо равно Last.
- Списком, имеющим форму item1, ..., itemn, где каждый item удовлетворяет вышеуказанным критериям.
Каждое значение представленное caseList должно быть уникальным внутри инструкции case; подмножества и списки не могут пересекаться.
Инструкции case может иметь завершающий раздел else:case selectorExpression of caseList1: statement1; ... caselistn: statementn; else statements; end
где statements – это разделенные точками с запятой (;) последовательности инструкций. При выполнении инструкции case, по крайней мере, одна из инструкций statement1 ... statementn выполняется. Какой бы caseList не имел равное значение, selectorExpression определяет инструкцию, которая должна быть выполнена. Если ни один из caseLists не имеет значения, равного selectorExpression, выполняется инструкция из раздела else (если таковой присутствует).
Инструкция casecase I of 1..5: Caption := 'Low'; 6..9: Caption := 'High'; 0, 10..99: Caption := 'Out of range'; else Caption := ; endэквивалентна вложенным условиям:
if I in [1..5] then Caption := 'Low'; else if I in [6..10] then Caption := 'High'; else if (I = 0) or (I in [10..99]) then Caption := 'Out of range' else Caption := ;Другие примеры использования инструкции case
case MyColor of Red: X := 1; Green: X := 2; Blue: X = 3; Yellow, Orange, Black: X := 0; end; case Selection of Done: Form1.Close; Compute: calculateTotal(UnitCost, Quantity); else Beep; end;
Циклы
Циклы позволяют вам повторно выполнять последовательность инструкций, используя контрольное условие или переменную для того, чтобы определять, должно ли выполнение прекратиться. Delphi имеет три вида циклов: repeat, while и for.
Вы можете использовать стандартные процедуры Break и Continue для контроля выполнения инструкций repeat, while и for. Процедура Break прерывает цикл в том месте, где она встречается, а процедура Continue начинает новую итерацию выполнения последовательности вложенных в цикл инструкций.
Инструкция Repeat
Синтаксис инструкции repeat:repeat statement1; ...; statementn; until expression
где expression – это выражение, возвращающее значение типа Boolean. (Последняя точка с запятой (;) перед until необязательна.) Инструкция repeat выполняет последовательность инструкций циклически, вычисляя значение expression после каждой итерации. Когда expression возвращает True, цикл прерывается. Последовательность инструкций выполняется по крайней мере однократно поскольку expression не вычисляется перед первой итерацией. Примеры инструкции repeat:
repeat K := I mod J; I := J; J := K; until J = 0; repeat Write('Enter a value (0..9): '); Readln(I); until (I >= 0) and (I <= 9);
Инструкция While
Инструкция while схожа с инструкцией repeat, за исключением того, что контрольное условие вычисляется перед первой итерацией. То есть, если контрольное условие возвращает значение false последовательность инструкций не будет выполнена ни разу.
Синтаксис инструкции while:while expression do statement
где expression – это выражение, возвращающее значение типа Boolean, а statement может быть составной инструкцией. Инструкция while циклически выполняет последовательность инструкций statement, проверяя значение expression перед каждой итерацией. До тех пор, пока expression возвращает значение True, выполнение продолжается.
Пример инструкции while:while Data[I] <> X do I := I + 1; while I > 0 do begin if Odd(I) then Z := Z * X; I := I p 2; X := Sqr(X); end; while not Eof(InputFile) do begin Readln(InputFile, Line); Process(Line); end;
Инструкция For
Инструкция for, в отличие от repeat и while, требует явно указать количество итераций. Синтаксис инструкции for:
for counter := initialValue to finalValue do statementили:
for counter := initialValue downto finalValue do statementгде:
counter – это локальная переменная (объявленная внутри блока, содержащего инструкцию for) порядкового типа без каких-либо спецификаторов.
initialValue и finalValue – это выражения, совместимые по присваиванию с counter.
statement - это простая или составная инструкция, которая не может изменять значение counter.
Инструкция for присваивает initialValue переменной counter, затем циклически выполняет statement, увеличивая или уменьшая counter после каждой итерации. (Синтаксис for...to увеличивает counter, а for...downto уменьшает.) Когда counter возвращает значение, равное finalValue, statement выполняется последний раз и цикл for прерывается. Другими словами statement выполняется однократно для каждого значения внутри диапазона между initialValue и finalValue. Если initialValue равно finalValue, statement выполняется однократно. Если initialValue больше finalValue в цикле for...to, или меньше чем finalValue в цикле for...downto, statement не выполняется ни разу. После прерывания цикла for (если прерывание не было вызвано процедурами Break илт Exit), значение counter становится неопределенным.
Предупреждение: Итератор counter не может быть изменен внутри цикла присвоением значения или передачей параметра по ссылке в процедуру. Нарушение этого правила приводит к выводу предупреждения при компиляции.Для целей обеспечения контроля выполнения инструкций внутри цикла выражения initialValue и finalValue вычисляются только однократно перед началом выполнениея цикла. То есть инструкция for...to почти всегда похожа (не полностью) на конструкцию while:
begin counter := initialValue; while counter <= finalValue do begin ... {statement}; counter := Succ(counter); end; end
Различие между этой конструкцией и инструкцией for...to состоит в том, что цикл while повторно вычисляет finalValue перед каждой итерацией. Это может привести к значительному снижению скорости выполнения, в том случае, когда finalValue представляет собой сложное для вычисления выражение. Кроме того, это означает, что изменения значения finalValue внутри statement могут влиять на выполнение цикла.
Примерыfor I := 2 to 63 do if Data[I] > Max then Max := Data[I]; for I := ListBox1.Items.Count - 1 downto 0 do ListBox1.Items[I] := UpperCase(ListBox1.Items[I]); for I := 1 to 10 do for J := 1 to 10 do begin X := 0; for K := 1 to 10 do X := X + Mat1[I,K] * Mat2[K,J]; Mat[I,J] := X; end; for C := Red to Blue do Check(C);
Итерации по элементам контейнеров при помощи инструкции For
Delphi поддерживает итерации типа для-элемента-в-наборе для контейнеров. Компилятором распознается следующие виды итераций по контейнерам:
- for Element in ArrayExpr do Stmt;
- for Element in StringExpr do Stmt;
- for Element in SetExpr do Stmt;
- for Element in CollectionExpr do Stmt;
- for Element in Record do Stmt;
Тип итератора Element должен совпадать по типу с типом элементов контейнера. При каждой итерации цикла в итератор помещается значение элемента набора. Так же как и в обычном цикле for, итератор должен быть объявлен внутри блока, содержащего инструкцию цикла for.
Предупреждение: Итератор не может быть изменен внутри цикла присвоением значения или передачей параметра по ссылке в процедуру. Нарушение этого правила приводит к выводу предупреждения при компиляции.В выражениях, возвращающих значения типа массив, тип массива может быть вектором или многоразмерным, фиксированной или нефиксированной длины (динамический массив). Массив проходится в порядке возрастания, начиная с нижней границы массива и заканчивая величиной, равной размеру массива минус один. Следующий программный код показывает примеры прохождения одномерного, многомерного и динамического массива:
type TIntArray = array[0..9] of Integer; TGenericIntArray = array of Integer; var IArray1: array[0..9] of Integer = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); IArray2: array[1..10] of Integer = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); IArray3: array[1..2] of TIntArray = ((11, 12, 13, 14, 15, 16, 17, 18, 19, 20), (21, 22, 23, 24, 25, 26, 27, 28, 29, 30)); MultiDimTemp: TIntArray; DynArray: TGenericIntArray; I: Integer; begin for I in IArray1 do begin { Do something with I... } end; { Indexing begins at lower array bound of 1. } for I in IArray2 do begin { Do something with I... } end; { Iterating a multidimensional array } for MultiDimTemp in IArray3 do // Indexing from 1..2 for I in MultiDimTemp do // Indexing from 0..9 begin { Do something with I... } end; { Iterating over a dynamic array } DynArray := TGenericIntArray.Create(1, 2, 3, 4); for I in DynArray do begin { Do something with I... } end; end.Следующий пример показывает прохождения по строковому выражению:
var C: Char; S1, S2: String; Counter: Integer; OS1, OS2: ShortString; AC: AnsiChar; begin S1 := 'Now is the time for all good men '+ 'to come to the aid of their country.'; S2 := ; for C in S1 do S2 := S2 + C; if S1 = S2 then WriteLn('SUCCESS #1') else WriteLn('FAIL #1'); OS1 := 'When in the course of human events'+ ' it becomes necessary to dissolve...'; OS2 := ; for AC in OS1 do OS2 := OS2 + AC; if OS1 = OS2 then WriteLn('SUCCESS #2') else WriteLn('FAIL #2'); end.Следующий пример показывает итерации по выражениям типа множество:
type TMyThing = (one, two, three); TMySet = set of TMyThing; TCharSet = set of Char; var MySet: TMySet; MyThing: TMyThing; CharSet: TCharSet; {$IF DEFINED(CLR)} C: AnsiChar; {$ELSE} C: Char; {$IFEND} begin MySet := [one, two, three]; for MyThing in MySet do begin // Do something with MyThing... end; CharSet := [#0..#255]; for C in CharSet do begin // Do something with C... end; end.
Для того, чтобы использовать конструкцию for-in с классами или интерфейсами, класс или интерфейс должны реализовывать соответсвующий функционал коллекции. Тип, который реализует функционал коллекции должен иметь следующие атрибуты:
- Экземпляр класса или интерфейса должен иметь общедоступный (public) метод с именем GetEnumerator(). Метод GetEnumerator() должен возвращать класс, интерфейс или запись.
- Экемпляр класса, интерфейса или записи, возвращаемые методом GetEnumerator() должны иметь метод MoveNext(). Метод MoveNext() должен возвращать значение типа Boolean.
- Экземпляр класса, интерфейса или записи, возвращаемые GetEnumerator() должны содержать доступное только для чтения свойство Current, которое должно возвращать значение типа, содержащегося в коллекции.
type TMyIntArray = array of Integer; TMyEnumerator = class Values: TMyIntArray; Index: Integer; public constructor Create; function GetCurrent: Integer; function MoveNext: Boolean; property Current: Integer read GetCurrent; end; TMyContainer = class public function GetEnumerator: TMyEnumerator; end; constructor TMyEnumerator.Create; begin inherited Create; Values := TMyIntArray.Create(100, 200, 300); Index := -1; end; function TMyEnumerator.MoveNext: Boolean; begin if Index < High(Values) then begin Inc(Index); Result := True; end else Result := False; end; function TMyEnumerator.GetCurrent: Integer; begin Result := Values[Index]; end; function TMyContainer.GetEnumerator: TMyEnumerator; begin Result := TMyEnumerator.Create; end; var MyContainer: TMyContainer; I: Integer; Counter: Integer; begin MyContainer := TMyContainer.Create; Counter := 0; for I in MyContainer do Inc(Counter, I); WriteLn('Counter = ', Counter); end.Следующие классы и их потомки поддерживают работу в конструкции for-in:
- Classes.TList
- Classes.TCollection
- Classes.TStrings
- Classes.TInterfaceList
- Classes.TComponent
- Menus.TMenuItem
- ActnList.TCustomActionList
- DB.TFields
- ComCtrls.TListItems
- ComCtrls.TTreeNodes
- ComCtrls.TToolBar
(Инструкции Case
ОтветитьУдалить.......
.......
где selectorExpression это любое выражение порядкового типа, меньшее, чем 32 бита (строковые типы)->(не больше, чем 32 бита)