Используется для бесконечных циклов - PullRequest
0 голосов
/ 30 июня 2019

Для чего нужны бесконечные циклы?Обычно это плохие новости в программировании, но есть ли время, когда вы хотите, чтобы цикл никогда не заканчивался?

1 Ответ

1 голос
/ 30 июня 2019

Бесконечные циклы - это плохие новости, только если они не предназначены или их использование имеет непреднамеренные последствия. Если вы используете их с намерением, нет никакой разницы с любой другой классификацией цикла, которую вы могли бы рассмотреть. Однако вы все равно будете ломать вещи, несмотря на намеренное использование. Обычно эта форма используется, когда вы хотите получить доступ к итератору или компоненту индекса после завершения цикла, например:

index = 0;
result = null;
for (;;)
    result = foo(index);
    if (bar(result))
        break;
    index += result;
use(index, result);

Обратите внимание, что изменение данных за пределами области действия цикла может быть очень нежелательным в зависимости от контекста, поэтому, действительно ли это хороший вариант использования, действительно зависит от контекста. Для другого подобного примера фактический итератор может быть объектом, желаемым вне цикла, но его инициализация в заголовке цикла не позволит получить доступ за пределами цикла. Бесконечный цикл решил бы эту проблему.

for (foo.iterator(); foo.hasNext(); ) {
    use(foo.next());
}
keep_using(foo.next());  // throws an error

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

for (;;) {
    if (condition1)
        break;
    else if (condition2)
        do_stuff();
    else if (condition3)
        break;
    else
        do_something();
}

Это можно переписать, используя три компонента цикла:

for (condition = true; condition; iteration) {
    if (condition1 || condition3)
        condition = false;
    else if (condition2)
        do_stuff();
    else
        do_something();
}

Однако, если мы внесем небольшое количество изменений (по крайней мере, с точки зрения символов на экране) в исходный код:

for (;;) {
    if (condition1);
        break;

    if (condition2);
        do_stuff();

    if (condition3);
        break;
    else
        do_something();
}

Переписывание становится тем, что требует от нас поиска этой дополнительной переменной:

for (condition = true; condition; iteration) {
    if (condition1)
        condition = false;

    if (condition2) {
        do_stuff();
        condition = true;
    }

    if (condition3)
        condition = false;
    else {
        do_something();
        condition = true;
    }
}

Это может быстро стать трудным для чтения и обслуживания по мере того, как тело цикла, и особенно возрастает сложность, например, если в condition действительно было много различных условий, таких как a || b || c < d || (e > f) && (a > f); или, цикл содержал несколько вложенных циклов. Хотя вы можете применить ту же логику к другой оригинальной измененной версии.

Еще один пример, связанный с читабельностью, включает в себя подробную инициализацию, хотя, по общему признанию, это не очень хороший вариант использования:

for (more_long = some_ridiculously_long.initialization_statement.longer_than.Long_Long_Mans_Sakeru_gummy();
    more_long < lots_of && more_long < break_conditions
    maybe_even_an_update_that_hangs_at_ninety_nine_percent) {
    ...
}
...