Предпосылка
Следующий код следует считать плохим, независимо от языка или желаемой функциональности:
while( true ) {
}
Поддерживающие аргументы
Петля while( true )
имеет плохую форму, потому что она:
- Разрывает подразумеваемый контракт цикла while.
- Объявление цикла while должно явно указывать условие выхода only .
- Подразумевает, что он зацикливается навсегда.
- Код внутри цикла должен быть прочитан, чтобы понять завершающий пункт.
- Повторяющиеся бесконечно циклы не позволяют пользователю завершить программу изнутри программы.
- Неэффективно.
- Существует несколько условий завершения цикла, включая проверку на "true".
- Склонен к ошибкам.
- Не легко определить, куда поместить код, который будет всегда выполняться для каждой итерации.
- Приводит к излишне сложному коду.
- Автоматический анализ исходного кода.
- Для поиска ошибок, анализа сложности программ, проверок безопасности или автоматического получения любого другого поведения исходного кода без выполнения кода указание начальных условий нарушения позволяет алгоритмам определять полезные инварианты, тем самым улучшая показатели автоматического анализа исходного кода.
- Бесконечные циклы.
- Если все всегда используют
while(true)
для циклов, которые не являются бесконечными, мы теряем способность к краткой связи, когда циклы фактически не имеют завершающего условия. (Возможно, это уже произошло, поэтому вопрос спорный.)
Альтернатива "Go To"
Следующий код является лучшей формой:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Преимущества
Нет флага. Нет goto
. Не исключение Легко изменить. Легко читать. Легко исправить. Дополнительно код:
- Изолирует знание рабочей нагрузки цикла от самого цикла.
- Позволяет кому-либо, поддерживающему код, легко расширять функциональность.
- Позволяет назначить несколько условий завершения в одном месте.
- Отделяет завершающее предложение от кода для выполнения.
- Безопаснее для АЭС. ; -)
Второй момент важен. Не зная, как работает код, если кто-то попросит меня сделать основной цикл, чтобы другие потоки (или процессы) имели некоторое время процессора, на ум приходят два решения:
Вариант № 1
Легко вставить паузу:
while( isValidState() ) {
execute();
sleep();
}
Вариант № 2
Выполнить переопределение:
void execute() {
super->execute();
sleep();
}
Этот код проще (следовательно, легче для чтения), чем цикл со встроенным switch
. Метод isValidState
должен только определять, должен ли цикл продолжаться. Рабочая лошадка метода должна быть абстрагирована в метод execute
, который позволяет подклассам переопределять поведение по умолчанию (трудная задача с использованием встроенных switch
и goto
).
Пример Python
Сравните следующий ответ (на вопрос по Python), который был размещен в StackOverflow:
- Петля навсегда.
- Попросите пользователя ввести свой выбор.
- Если пользовательский ввод «перезапустить», продолжайте цикл навсегда.
- В противном случае прекратите цикл навсегда.
- Конец.
Код
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Versus:
- Инициализировать выбор пользователя.
- Цикл, пока пользователь выбирает слово «перезагрузка».
- Попросите пользователя ввести свой выбор.
- Конец.
Код
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Здесь while True
приводит к вводящему в заблуждение и чрезмерно сложному коду.