Должен ли я использовать return/continue вместо if-else?

В C, С++ и С# при использовании условия внутри функции или оператора цикла можно как можно раньше использовать оператор continue или return и избавиться от ветки else инструкции if-else. Например:

while( loopCondition ) {
    if( innerCondition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

становится

 while( loopCondition ) {
    if( innerCondition ) {
        //do some stuff
        continue;
    }
    //do other stuff
}

и

void function() {
    if( condition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

становится

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

Вариант "после" может быть более читаемым, если ветки if-else длинны, потому что это изменение исключает отступы для ветки else.

Является ли такое использование return/continue хорошей идеей? Существуют ли какие-либо проблемы с обслуживанием или читабельностью?

Ответ 1

Компилятор почти наверняка создаст тот же код. Даже если это не так, разница будет, вероятно, неактуальной. Следовательно, соответствующий аргумент, конечно же, как люди его прочтут.

Поэтому вопрос заключается в том, как подобны "//делают некоторые вещи" и "делают другие вещи". Если они концептуально похожи, используйте if/else. Если они концептуально отличаются, используйте continue/return.

Ответ 2

Мой личный подход к выбору одного заключается в том, что если тело части if очень короткое (максимум 3 или 4 строки), имеет смысл использовать вариант return/continue. Если тело длинное, сложнее отслеживать поток управления, поэтому я выбираю версию else.

Как правило, этот подход ограничивает использование стиля return/continue, чтобы пропустить некоторые данные и избежать дальнейшей обработки, а не обрабатывать это, используя один из следующих методов (который лучше подходит if/else).

Ответ 3

Это зависит немного от того, как долго ветки. Использование return/continue, которое вы описываете, хорошо, если начальная проверка if коротка, а тело длинное. Если части if и else длинны, я бы выделил их для разделения функций.

Я рекомендую читать Code Complete, он много обсуждает такие вещи.

Ответ 4

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

 if (termination condn) 
      return;
 // code 
 // code

к

if (success condn)
{
  // code
  // code
}
else
 return;

Это облегчает чтение и понимание кода.

Ответ 5

Ответ glib заключается в том, что все зависит.

Мое общее мнение состоит в том, что если condition - редкий, защитный (например, проверка на нуль) или условие ошибки, то я склонен использовать return или continue

Если это ожидаемый случай, я, как правило, использую ваш первый подход.

Обратите внимание, однако, что я сказал "склонность". Граница между этими условиями неопределенна и может меняться в зависимости от проекта и с кем я работаю.

Ответ 6

Я обычно предпочитаю

while( loopCondition ) {
    if( innerCondition ) {
        DoStuff();
    } else {
        DoOtherStuff(); 
    }
}

continue может быть трудно следовать, если длина DoStuff прошла 1-2-строчный порог (и его довольно легко упустить намерение). Это похоже на хорошую возможность реорганизовать логику на некоторые более мелкие методы.

Ответ 7

Не жертвуйте удобочитаемостью для преждевременной оптимизации.

Например:

void function() {
    if( condition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

в большинстве случаев двоичный эквивалент

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

(т.е. полученный код, вероятно, тот же). Но читаемость первого намного лучше, потому что вы можете ясно видеть, что код будет либо X, либо Y.

Ответ 8

1) Ввод или проверка состояния объекта. Следующий код:

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

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

2) Многоступенчатая обработка. В то время как /continue хорош, когда петля выталкивает элементы из некоторой коллекции и обрабатывает их многоступенчато:

while(foo = bar.getNext()) {
   if(foo.empty())
       continue;
   if(foo.alreadyProcessed())
       continue;
   // Can we take a shortcut?
   if(foo.tryProcessThingsYourself())
       continue;
   int baz = foo.getBaz();
   if(baz < 0) {
       int qux = foo.getQux();
       if(qux < 0) {
         // Error - go to next element
         continue;
       }
   }
   // Finally -- do the actual processing
   baz = baz * 2;
   foo.setBaz(baz);
}

В примере показано, насколько естественно использовать продолжить в сценарии, когда выполняются серии многоступенчатой ​​обработки, когда каждая обработка может быть прервана различными условиями в разных местах.

Примечание: плинтус опубликовал реальный пример, который следует за тем, что сказано в 2).

3) Общее правило. Я использую продолжить и возвращать, когда это соответствует тому факту, что что-то было прервано. Я использую else, когда else является частью фактической обработки.

Ответ 9

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

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

Ответ 10

как говорили другие люди, используйте только return/continue, если что-то не так.

Лично я использую только продолжение, если можно писать на одной строке, например:

while( loopCondition ) {
    if( innerCondition ) continue;

    //do other stuff
}

Если это невозможно записать так, как только код не станет уродливым, тогда if/else.

Ответ 11

Для усмешек я сделал поиск по моей кодовой базе для "continue"; просто чтобы понять, где он используется. Мы используем, если 695 раз по 59 проектам в одном решении, примерно 1500 исходных файлов.

Основные способы, которыми я их использую, - это быстрый фильтр:

foreach (Frobozz bar in foo) {
    if (QuickFilterExclude(bar))
        continue;
    // extensive processing
}

Восстановление из ожидаемого исключения:

foreach (Frobozz bar in foo) {
    Baz result = new Baz(kDefaultConfiguration);
    try {
        Baz remoteResult = boo.GetConfiguration();
    }
    catch (RemoteConnectionException) {
        continue;
    }
    result.Merge(remoteResult);
    ReportResult(result);
}

И, наконец, в государственной технике.

Ответ 12

Обычно я использую метод if-return при выпрыгивании из метода или цикла, потому что ничего не поделаешь.

Если тело длиннее, потому что выполняется существенная работа, я предлагаю использовать if-else и, возможно, использовать #region, чтобы дать блокам разумное имя и легко их сместить для людей, чтобы изучить поток управления. Это или сделать отдельные методы:)

Ответ 13

В моем коде было следующее:

    while(){
      boolean intersect = doesIntersect(interval_1,interval_2);
      if(!intersect){
         array.add(interval_2);
         if(// another condition){
            // Do some thing here
         }
         continue;
      }
      // other stuff to do if intersect
    }

Сбив с толку, следует ли использовать продолжить там или использовать else, но я решил, что внутреннее условие if может сделать другое недочитанное, поэтому я использовал continue.

Я думаю, что читаемость важна!