Принципиальная разница между циклом FOR
и циклом WHILE
заключается в том, что для цикла FOR
число итераций ограничено константой, известной до запуска цикла, тогда как для WHILE
цикл, число итераций может быть неограниченным, неизвестным или бесконечным.
В результате язык, предлагающий только циклы WHILE
, является Turing-complete, а язык, предлагающий только циклы FOR
, - нет.
Итак, первая очевидная вещь, которую может сделать только цикл WHILE
, - это бесконечный цикл. Вещи, которые легко моделируются как бесконечные циклы, это, например, веб-сервер, клиент Netflix, игровой цикл, цикл событий GUI или операционная система:
WHILE (r = nextHttpRequest):
handle(r)
END
WHILE (p = nextVideoStreamPacket):
frame = decode(p)
draw(frame)
END
WHILE (a = playerAction):
computeNextFrame(a)
END
WHILE (e = nextEvent):
handle(e)
END
WHILE (s = sysCall):
process(s)
END
Хороший пример, где цикл не бесконечен, но граница не известна заранее, - это (как вы уже упоминали в своем вопросе) запрос пользовательского ввода. Примерно так:
WHILE (askBoolean("Do you want to play again?")):
playGame()
END
Другим хорошим примером является обработка строки, подобной C, где длина строки неизвестна, но конечна. Это та же самая ситуация для связанного списка или для любой структуры данных, где есть понятие «следующий», но не понятие «размер», вместо этого есть некоторое значение часового, которое отмечает конец (например, NUL
-определенные строки в C) или способ проверить, есть ли следующий элемент (например, Iterator
в Java):
WHILE ((element = getNext()) != END_MARKER):
process(element)
END
WHILE (hasNextElement):
process(getNext())
END
Существуют также ситуации, когда можно обрабатывать с помощью петли FOR
, но петля WHILE
более элегантна. Одна ситуация, о которой я могу подумать, состоит в том, что оценка числа итераций заранее известна, она постоянна, но известная граница смехотворно велика, и фактическое количество требуемых итераций значительно меньше, чем ограничение.
К сожалению, я не могу придумать хороший реальный пример этого, может быть, кто-то другой может. Цикл FOR
для этого обычно будет выглядеть следующим образом, чтобы пропустить итерации от фактического числа итераций до верхней границы:
FOR (i FROM 1 TO $SOME_LARGE_UPPER_BOUND):
IF (terminationConditionReached):
NOOP()
ELSE:
doSomethingInteresting()
END
END
Что было бы гораздо лучше выразить как
WHILE (NOT terminationConditionReached):
doSomethingInteresting()
END
Использование FOR
цикла может иметь смысл в этой ситуации, если значение i
представляет интерес:
FOR (i FROM 1 TO $SOME_LARGE_UPPER_BOUND):
IF (terminationConditionReached):
NOOP()
ELSE:
doSomethingInterestingWithI(i)
END
END
Последняя ситуация, о которой я могу подумать, когда цикл WHILE
более уместен, чем цикл FOR
, даже если число итераций ограничено известной константой, если эта константа не "семантически интересна" для петли.
Например, игровой цикл для крестики-нолики требует не более 9 ходов, поэтому его можно смоделировать как цикл FOR
:
FOR (i FROM 1 TO 9):
IF (player1Won OR player2Won):
NOOP
ELSE:
makeMove()
END
END
Но число "9" здесь не очень интересно. Гораздо интереснее, есть ли у одного игрока или доска заполнена:
WHILE (NOT (player1Won OR player2Won OR boardFull)):
makeMove()
END
[Примечание: по крайней мере, если вы играете против ребенка, это также является примером второй до последней ситуации, а именно, что известно, что верхняя граница равна 9, но многие игры будут короче 9 ходов , Однако я все еще хотел бы найти пример для этого, который не является также примером семантически неинтересного условия завершения.]
Итак, у нас есть два класса ситуаций: один, где цикл FOR
просто не может быть использован (когда граница неизвестна, не существует или бесконечна), и один, где цикл FOR
может использоваться, но цикл WHILE
является более раскрывающим намерение .