Инструкции определяют алгоритмические действия внутри программы. Простые инструкции, такие как присваивание и вызовы процедур могут быть объединены в циклы, условные инструкции и другие структуры.
Составные инструкции внутри блоков и секциях 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 бита)