break и continue
Два оператора работают с циклами, чтобы упростить написание некоторых сценариев. Оператор continue завершает текущий проход цикла for или repeat. Все дальнейшие операторы в текущем цикле пропускаются, и выполнение продолжается с логического теста (если имеется), который контролирует начало следующего повторения. break полностью завершает цикл for или repeat, отправляя управление сразу оператору, следующему после цикла.
Рассмотрим следующий пример использования команд break и repeat:
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAIL3 default {}; param avail3_obj {AVAIL3}; param avail3_dual {AVAIL3}; let avail[3] := 0; param previous_dual default Infinity; repeat { let avail[3] := avail[3] + 1; solve; if Time[3].dual = previous_dual then continue; let AVAIL3 := AVAIL3 union {avail[3]}; let avail3_obj[avail[3]] := Total_Profit; let avail3_dual[avail[3]] := Time[3].dual; if Time[3].dual = 0 then break; let previous_dual := Time[3].dual; } display avail3_obj, avail3_dual;
Согласно логики работы сценария: запись в таблицу производится только тогда, когда есть изменение в двойном значении, связанном с avail[3]. После решения, мы проверяем, равно ли новое двойное значение предыдущему:
if Time[3].dual = previous_dual then continue;
Если да, тогда для этого значения avail[3] не совершается никаких дальнейших действий, а оператор continue переводит к концу текущего прохода. Выполнение кода продолжается с места начала цикла следующего прохода. После добавления записи в таблицу мы проверяем, не снижено ли двойное значение до нуля:
if Time[3].dual = 0 then break;
Если это так, тогда оператор break прекращает выполнение цикла. Дальнейшее выполнение передается команде display, которая следует за циклом в сценарии. Поскольку оператор repeat, в этом примере не имеет условия while или until, для завершения он полагается на оператор break.
Когда break или continue находится во вложенном цикле, он применяется только к этому внутреннему циклу. Эта правило обычно дает желаемый эффект. В качестве примера рассмотрим, как можно выполнить анализ чувствительности для каждого отдельного avail[t]. Цикл repeat будет вложен в цикл for{t in 1..T}, но операторы continue и break будут применяться к внутреннему repeat.
Существуют ситуации, в которых логика сценария требует выхода из нескольких циклов. Например, в сценарии выше мы можем представить, что вместо остановки, когда Time[3].dual равен нулю:
if Time[3].dual = 0 then break;
мы хотим остановить выполнение, когда Time[t].dual снижается ниже 2700 для любого t. Может показаться, что одним из способов реализации этого критерия является:
for {t in 1..T} if Time[t].dual < 2700 then break;
Однако, это утверждение не имеет желаемого эффекта, потому что break применяется только к внутреннему циклу for, который его содержит, а не к внешнему циклу повторения, как мы того желаем. В таких ситуациях мы можем дать имя циклу, а break или continue могут указать по имени цикл, к которому он должен применяться. Используя эту функцию, внешний цикл в нашем примере может быть назван sens_loop:
repeat sens_loop {
и тест на завершение внутри него может ссылаться на его имя:
for {t in 1..T} if Time[t].dual < 2700 then break sens_loop;
Имя цикла появляется сразу после repeat или for, и после break или continue.