Как я могу переписать это (чисто) без gotos?

Как я могу сделать это чисто без gotos?

loop:
  if(condition1){
    something();
  } else if (condition2) {
    somethingDifferent();
  } else {
    mostOfTheWork();
    goto loop;
  }

Я бы тоже предпочел не использовать перерывы. Кроме того, ожидается, что он будет выполнять цикл несколько (adv 40) раз, прежде чем делать что-то еще, поэтому часть mostOfTheWork, скорее всего, будет как можно выше, даже если просто для удобства чтения. Заранее спасибо.

РЕДАКТИРОВАТЬ: Это было опубликовано из-за неправильного представления о том, что оптимизатор компилятора плохо работал с перерывами, что, хотя и глупо с самого начала, я доказал для себя неправильно в ходе экспериментов (производительности). С другой стороны, спасибо за ваши ответы; они были интересны для чтения в различных стилях.


person Jared Pochtar    schedule 02.04.2010    source источник
comment
любой конкретный язык; Руби, PHP, С#, Java и т. д.?   -  person Kane    schedule 03.04.2010
comment
Почему бы не использовать перерывы? Вот для чего они там и нужны для этого случая, если только я не настолько умен, что, вероятно, так и есть. В качестве примечания: возможно, вы захотите указать, на каком это языке, это может иметь значение.   -  person Nick Craver    schedule 03.04.2010
comment
Укажите ваши требования по отказу от использования перерывов. Как правило, это не относится к языку и разрешено к использованию, так почему бы их не использовать?   -  person Natalie Adams    schedule 03.04.2010
comment
Да, серьезно, почему нет break? Это для школы или что?   -  person SamB    schedule 03.04.2010
comment
Из любопытства, с чего вы взяли, что оптимизация компилятора будет плохо работать с перерывами?   -  person Stephen Canon    schedule 03.04.2010
comment
Один из ключевых принципов структурированного программирования заключается в том, что управляющая структура должна иметь ровно один вход и ровно один выход. Это позволяет точно знать, где и как происходит выход управляющей структуры, и что в этот момент будет верным. (Прочитайте заявление Дейкстры GOTO, которое считается вредным, а затем прочтите раздел Дейкстры «Структурированное программирование» Даля, Дейкстры и Хоара.) Использование нескольких операторов break по определению нарушает это правило.   -  person John R. Strohm    schedule 03.04.2010
comment
это смехотворно, что вы «не хотите использовать перерывы». совершенно странно.   -  person Fattie    schedule 07.07.2014


Ответы (7)


Ясно, что вы вырветесь из цикла, если сработает одно из условий.

    while ((!condition1) && (!condition2)) {
      MostOfTheWork();
    }
    if (condition1) {
      something();
    } else if (condition2) {
      somethingDifferent();
    }

Итак, зациклитесь, пока ни одно из условий не сработало, а затем посмотрите, какое из них вам помогло.

Сейчас кто-то будет кричать, что я оценил условия больше, чем нужно. В их пользу модифицированная версия:

{
  bool t1, t2;
  while ((!(t1 = condition1)) && (!(t2 =condition2))) {
    MostOfTheWork();
  }
  if (t1) {
    something();
  } else if (t2) {
    somethingDifferent();
  }
}
person John R. Strohm    schedule 02.04.2010
comment
+1 Я думаю, что это решение, демонстрирующее самую острую наблюдательность. - person Decent Dabbler; 03.04.2010
comment
@Якоби: Нет! Вспомните, что стандарты C и C++ очень четко требуют, чтобы оператор && выполнял ускоренную оценку. Если срабатывает первая ветвь &&-выражения, вторая ветвь не оценивается. - person John R. Strohm; 03.04.2010

Без перерывов?

function foo(){
  if(condition1){
    something();
    return;
  } else if (condition2) {
    somethingDifferent();
    return;
  }
  mostOfTheWork();
  foo(); //(Tail recursive for those worried about stack overflows)
}

Тем не менее, разрывы существуют для управления потоком, они намного понятнее в отношении того, что они делают, чем goto, поэтому я бы рекомендовал их использовать. Однако в этом случае я бы порекомендовал ответ @John как правильный способ сделать это.

person Yacoby    schedule 02.04.2010
comment
Не все языки оптимизируют хвостовые вызовы. Это по-прежнему может вызывать переполнение стека во многих языках. - person R Samuel Klatchko; 03.04.2010
comment
В этом, десятом году 21-го века, компилятор производственного качества, который не оптимизирует хвостовые вызовы, безнадежно мертв. Идея существует уже более трех десятилетий: прочтите серию заметок лаборатории ИИ MIT Lambda: the Ultimate.... - person John R. Strohm; 03.04.2010

Никаких гот и клювов. Как всегда без чистоты, субъективно

 do {
   if ( condition1 )
     something();
   else if( condition2 )
     somethingElse();
   else
     mostOfTheWork();
 } while( !(condition1 || condition2) );

Это, конечно, невероятно глупо. Просто используйте перерыв.

person Logan Capaldo    schedule 02.04.2010

Вам, вероятно, вбили в голову профессора CS, что это плохо и приведет к хаосу в вашем коде. Gotos на самом деле довольно эффективны, если их правильно и целенаправленно использовать. Вот почему большинство языков программирования не отказались от него.

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

person ATL_DEV    schedule 03.04.2010

Поскольку вы не указали конкретный язык, в некоторых языках есть continue, next или skip, которые вы можете использовать вместо goto.

person Forgotten Semicolon    schedule 02.04.2010

По моему мнению, эта версия кода наиболее четко передает поток программы потомкам и наиболее легко расширяется. Да, я использую break. Я не могу придумать ни одной реальной причины не делать этого.

while(true)
{
    if (condition1)
    {
        something();
        break;
    }
    if (condition2)
    {
        somethingDifferent();
        break;
    }
    mostOfTheWork();
}

Если вы действительно не хотите использовать break, вы можете использовать goto, чтобы выйти из цикла, или использовать return, чтобы выйти из функции (если этот цикл является частью более крупной функции, вам придется провести рефакторинг).

while(true)
{
    if (condition1)
    {
        something();
        goto exit;
    }
    if (condition2)
    {
        somethingDifferent();
        goto exit;
    }
    mostOfTheWork();
}
exit:

Or

while(true)
{
    if (condition1)
    {
        something();
        return;
    }
    if (condition2)
    {
        somethingDifferent();
        return;
    }
    mostOfTheWork();
}

И если вы отказываетесь использовать любое управление потоком, кроме if и while, как насчет этого:

bool ok = true;
while(ok)
{
    if (condition1)
    {
        something();
        ok = false;
    }
    if (ok && condition2)
    {
        somethingDifferent();
        ok = false;
    }
    if (ok)
    {
        mostOfTheWork();
    }
}

Кроме того, см. мой канонический ответ на этот вопрос (и голосуй за!)

person John Wu    schedule 02.07.2014

person    schedule
comment
Штопать. Вы печатали быстрее, молодец. Приятно знать, что я придумал то же самое решение. - person Jed Daniels; 03.04.2010