Должен ли я использовать оператор return / continue вместо if-else? - PullRequest
28 голосов
/ 08 июня 2009

В C, C ++ и 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 хорошей идеей? Есть ли какие-либо проблемы с обслуживанием или читабельностью?

Ответы [ 13 ]

31 голосов
/ 08 июня 2009

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

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

13 голосов
/ 08 июня 2009

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

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

12 голосов
/ 08 июня 2009

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

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

11 голосов
/ 08 июня 2009

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

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

до

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

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

6 голосов
/ 08 июня 2009

Глупый ответ: все зависит.

По моему общему мнению, если condition - это редкое, сторожевое (например, проверка на ноль) или состояние ошибки, то я склонен использовать return или continue

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

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

4 голосов
/ 08 июня 2009

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

Например:

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

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

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

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

4 голосов
/ 08 июня 2009

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

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

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

3 голосов
/ 08 июня 2009

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);
}

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

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

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

2 голосов
/ 08 июня 2009

Для ухмылки я выполнил поиск по базе кода моей компании для «продолжения»; просто чтобы понять, где он используется. Мы используем 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);
}

И, наконец, в государственном аппарате.

2 голосов
/ 08 июня 2009

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

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

while( loopCondition ) {
    if( innerCondition ) continue;

    //do other stuff
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...