Распечатать страницу

Управляющие конструкции в VFP

« Назад

Реализуют ветвления IF … ENDIF, выбор DO CASE … ENDCASE и циклы DO WHILE … ENDDO, FOR EACH … ENDFOR и FOR … ENDFOR. Состоят из команд IF, ENDIF, DO CASE и т. д.

Конструкции могут быть вложенными. Каждая конструкция может содержать любую другую конструкцию.

Конструкция

IF lExpression [THEN]
Commands
ENDIF

выполняет команды Commands, если логическое выражение lExpression вычисляется со значением .T.

Конструкция

IF lExpression [THEN]
Commands1
ELSE

Commands2
ENDIF

выполняет команды Commands1, если логическое выражение lExpression вычисляется со значением .T., или выполняет команды Commands2 – в противном случае.

Пример. Выводятся все положительные элементы одномерного массива someArray, а также их общее количество. При отсутствии положительных элементов печатается соответствующее сообщение.

declare someArray[10]

&& Все элементы массива будут равны –2

store –2 to someArray

&& Теперь массив будет иметь 2 положительных элемента

someArray[2] = 1

someArray[5] = 3

numberOfPositiveElements = 0

for each element in someArray

&& Проверяем знак элемента массива

if element > 0 then

&& Элемент положителен. Увеличиваем numberOfPositiveElements

&& и печатаем значение элемента

numberOfPositiveElements = numberOfPositiveElements + 1

? element

endif

next

if numberOfPositiveElements > 0 then

? "Число положительных элементов в массиве someArray: ", ;

numberOfPositiveElements

else

? "В массиве someArray нет положительных элементов!"

endif

Функция

IIF(lExpression, eExpression1, eExpression2)

возвращает результат выражения eExpression1, если логическое выражение lExpression вычисляется со значением .T., или результат выражения eExpression2 – в противном случае. Также функция вернет результат выражения eExpression2, если lExpression вычисляется со значением . NULL.

Функцию следует использовать, если это возможно, взамен конструкции IF ... ENDIF. Особенно она полезна при работе с отчетами и этикетками.

Функции IIF( ) выполняется быстрее, чем эквивалентная конструкция IF ... ENDIF.

Пример 1. Заменяются отрицательные элементы массива на число –1, а положительные – на число 1.

declare someArray[10]

store –2 to someArray

someArray[2] = 1

someArray[5] = 3

someArray[9] = 0

for k = 1 to Alen(someArray)

if someArray[k] != 0 then

someArray[k] = Iif(someArray[k] > 0, 1, –1)

endif

next

&&

&& Контрольный вывод

for each element in someArray

?? element  && Напечатает: –1  1  –1  –1  1  –1  –1  –1  0  –1

next

Пример 2 (приводится в справке VFP):

close databases

open database (Home(2) + 'Data\TestData')

use Employee

scan

&& Печатаем либо сообщение 'Описания нет!', либо содержимое поля Notes

? Iif(Empty(Notes), 'Описания нет!', Notes)

endScan

Конструкция

DO CASE
CASE lExpression1
                   [Commands1]

         [CASE lExpression2
                  
[Commands2]]

         ...
         [CASE lExpressionN
                  
[CommandsN]]

         [OTHERWISE
                   [Commands]]
         ENDCASE

выполняет первый набор команд, для которого логическое выражение lExpression вычисляется со значением .T.

Так, первоначально оценивается выражение lExpression1 и если оно возвращает .T., то выполнятся команды Commands1 и управление будет передано оператору, следующему за командой ENDCASE. В противном случае, если lExpression1 – это .F., оценивается выражение lExpression2 и т. д.

Если все логические выражения lExpression вернут .F. и если имеется команда OTHERWISE, то будут выполнены команды Commands, следующие за этой командой.

Пример. Функция DoOperation( ) возвращает сумму, разность, произведение или частное двух своих первых параметров в зависимости от значения третьего параметра. Функция вернет .F., если третий параметр, задающий вид операции, имеет недопустимое значение.

op = '+'                               && или '–', или '*', или '/', , или '^', или ':'

a = 5

b = 2

x = DoOperation(a, b, op)

function DoOperation(a, b, op)

do case

case op == '+' or op == '–' or op == '*' or op == '/' or op == '^'

x = a &op b         && Используем макроподстановку

                                            case op == ':'

                                               x = a / b

                                            otherwise

                                               x = .F.

                                            endcase

                                            return x

endFunc

Функция

ICASE(lCondition1, eResult1 [, lCondition2, eResult2] ...
[, eOtherwiseResult])

оценивает логические выражения и возвращает один из возможных результатов. Число пар передаваемых функции параметров не должно быть более 100.

Параметры:

lCondition – оцениваемое логическое выражение. Если оно вычисляется со значением .F., то оценивается следующее выражение, если – со значением .T., то функции вернет результат соответствующего выражения eResult.

eOtherwiseResult – результат, возвращаемый, если все выражения lCondition оцениваются со значением .F. Если параметр опущен и все lCondition имеют значение .F., то функция вернет NULL.

Если функция ICASE( ) использована в выражении фильтра, например в опции FOR или WHERE, то необходимо проследить, чтобы функция SYS(3055) задавала необходимый уровень допустимой сложности выражений.

Пример. В выше приведенной функции DoOperation( ) вместо конструкции DO CASE … ENDCASE употребляется функция ICASE( ).

function DoOperation(a, b, op)

return Icase(op == '+', a + b, op == '–', a – b, op == '*', a * b, ;

op == '/' or op == ':', a / b, op == '^', a^b, .F.)

endFunc

Конструкция

DO WHILE lExpression
                   Commands
                   [LOOP]

                   [EXIT]
         ENDDO

обеспечивает выполнение команд Commands до тех пор, пока истинно логическое выражение lExpression.

Конструкция DO WHILE … ENDDO может включать команды LOOP и EXIT.

LOOP – передает управление на начало конструкции, то есть команде DO WHILE.

EXIT – выполняет выход из конструкции, передавая управление оператору, следующему за командой ENDDO.

Пример (приводится в справке VFP). Вычисляется общая стоимость имеющихся в наличии товаров, цена которых не менее 20 у. е.

close databases

open database (Home(2) + 'Data\TestData')

use Products

set talk off

gnStockTot = 0

&& Просматриваем все записи таблицы Products

do while .T.

                                            if eof( )

                                               exit

                                            endif

                                            if unit_price < 20

                                               skip   && Переходим на следующую запись

                                               loop

                                            endif

                                            gnStockTot = gnStockTot + in_stock

                                            skip      && Переходим на следующую запись

enddo

clear

? gnStockTot                      && Выводим результат

Замечание. С позиции структурного программирования приведенный цикл правильнее записать следующим образом:

do while .T. and not eof( )

                                            if unit_price >= 20 then

                                               gnStockTot = gnStockTot + in_stock

                                            endif

                                            skip      && Переходим на следующую запись

enddo

С функцией IIF( ) цикл будет еще короче:

do while .T. and not eof( )

gnStockTot = gnStockTot + Iif(unit_price < 20, 0, in_stock)

skip      && Переходим на следующую запись

enddo

Конструкция

FOR EACH Var [AS Type [OF Class Library]] IN Group [FOXOBJECT]
                   Commands
                   [EXIT]

                   [LOOP]
         ENDFOR | NEXT [Var]

обеспечивает выполнение команд Commands для каждого элемента Var массива или коллекции Group.

Опция и параметры:

Type – базовый класс, имя класса или библиотеки типа (только для Intellisense).

Class Library – библиотека классов, содержащая базовый класс, имя класса или библиотеки типа (только для Intellisense).

FOXOBJECT – указывает, что элемент Var будет ссылаться только на VFP-объекты (не COM).

Команды LOOP и EXIT имеют такое же действие, как и в конструкции DO WHILE … ENDDO: LOOP передает управление на начало цикла, EXIT – обеспечивает выход из цикла (прерывание цикла).

Пример 1. См. в описании конструкции IF … ENDIF.

Пример 2 (приводится в справке VFP). Создается экземпляр Microsoft Excel и добавляется новая рабочая книга. Печатаются имена элементов коллекции, которой рабочая книга является.

oExcel = CreateObject("Excel.Application")

oExcel.Workbooks.Add

for each Sheet in oExcel.Sheets

?? Sheet.Name, " "  && Напечатает: Лист1 Лист2 Лист3

next Sheet

Пример 3. Выводятся имена файлов всех форм, входящих в активный проект.

&& Проект должен быть открыт

&& Одним из свойств объекта Project является коллекция Files

for each file in _VFP.ActiveProject.Files

                                            && Проверяем, является ли файл формой

                                            if file.Type = 'K' then

                                               ? file.Name && Печатаем имя файла

                                            endif

endfor

Конструкция

FOR Var = nInitialValue TO nFinalValue [STEP nIncrement]
                   Commands
                   [EXIT]

                   [LOOP]
         ENDFOR | NEXT

обеспечивает выполнение команд Commands заданное число раз.

Если nIncrement > 0, то цикл выполняется до тех пор, пока VarnFinalValue.

Если nIncrement < 0, то цикл выполняется до тех пор, пока VarnFinalValue.

Значение 0 для параметра nIncrement недопустимо.

На первой итерации Var = nInitialValue.

Каждое новое значение параметра Var, вычисляемое при передаче управления на начало цикла, равно Var = Var + nIncrement. (Управление на начало цикла передают команды ENDFOR | NEXT и LOOP.)

Если параметр nIncrement опущен, то он принимается равным 1.

Команды LOOP и EXIT имеют такое же действие, как и в конструкции DO WHILE … ENDDO.

Замечание. Параметры nInitialValue, nFinalValue и nIncrement являются числовыми выражениями, вычисляемыми при входе в цикл, поэтому изменение значений nInitialValue, nFinalValue и nIncrement, если они являются переменными, внутри цикла не окажет влияния на число выполняемых итераций. Однако изменение параметра Var внутри цикла влияет на число его выполнений.

Пример 1. См. в описании функции IIF( ).

Пример 2. Выводится номер первой строки двумерного массива, имеющей отрицательный элемент.

declare someArray(4, 5)

someArray = 2

someArray(3, 2) = –1

someArray(4, 3) = –1

&& Массив someArray:

&&

2

2

2

2

2

&&

2

2

2

2

2

&&

2

–1

2

2

2

&&

2

2

–1

2

2

numberOfCols = Alen(someArray, 2)       && Число столбцов в массиве

flag = .F.

for iRow = 1 to Alen(someArray, 1)

                                            for iCol = 1 to numberOfCols

                                               if someArray(iRow, iCol) < 0 then

? "Номер первой строки с отрицательным элементом ", iRow

                                               flag = .T.

                                               exit    && Выход из внутреннего цикла

                                            endif

  endfor

  if flag then                         && Строка найдена

                                            exit       && Выход из вешнего цикла

  endif

endfor

if not flag

? "В массиве нет отрицательных элементов!"

endif

Замечание. С позиции структурного программирования приведенный цикл лучше переписать следующим образом:

numberOfCols = Alen(someArray, 2)       && Число столбцов в массиве

flag = .F.

iRow = 0

do while iRow < Alen(someArray, 1) and not flag

  iRow = iRow + 1

                                            iCol = 0

                                            do while iCol < numberOfCols and not flag

                                            iCol = iCol + 1

                                               if someArray(iRow, iCol) < 0 then

? "Номер первой строки с отрицательным элементом ", iRow

                                               flag = .T.

                                            endif

  enddo

enddo