Должен ли я вернуться из функции раньше или использовать оператор if? [закрыто]

Я часто писал такую ​​функцию в обоих форматах, и мне было интересно, предпочитается ли один формат другому, и почему.

 public void SomeFunction(bool someCondition)
{
    if (someCondition)
    {
        // Do Something
    }
}

или

 public void SomeFunction(bool someCondition)
{
    if (!someCondition)
        return;

    // Do Something
}

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

260 голосов | спросил 10 revs, 8 users 46%
Rachel
1 Jam1000000amThu, 01 Jan 1970 03:00:00 +030070 1970, 03:00:00

19 ответов


346

Я предпочитаю второй стиль. Сначала получите недопустимые случаи, просто выйдя или, соответственно, исключив исключения, поместите туда пустую строку, затем добавьте «реальное» тело метода. Мне легче читать.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
136

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

 public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (someCondition)
    {
        if (name != null && name != "")
        {
            if (value != 0)
            {
                if (perms.allow(name)
                {
                    // Do Something
                }
                else
                {
                    reval = PERM_DENY;
                }
            }
            else
            {
                retval = BAD_VALUE;
            }
        }
        else
        {
            retval = BAD_NAME;
        }
    }
    else
    {
        retval = BAD_COND;
    }
    return retval;
}

более читабельна, чем

 public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    if (!someCondition)
        return BAD_COND;

    if (name == null || name == "")
        return BAD_NAME;

    if (value == 0)
        return BAD_VALUE;

    if (!perms.allow(name))
        return PERM_DENY;

    // Do something
    return SUCCESS;
}

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

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
31

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

Тем не менее, если функция требует некоторых данных при ее вызове, я обычно собираюсь исключить исключение (см. пример), а не просто возвращаться.

 public int myFunction(string parameterOne, string parameterTwo) {
  // Can't work without a value
  if (string.IsNullOrEmpty(parameterOne)) {
    throw new ArgumentNullException("parameterOne");
  } 
  if (string.IsNullOrEmpty(parameterTwo)) {
    throw new ArgumentNullException("parameterTwo");
  }

  // ...      
  // Do some work
  // ...

  return value;
}
ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
19

Я предпочитаю раннее возвращение.

Если у вас есть одна точка входа и одна точка выхода, вам всегда нужно отслеживать весь код в вашей голове вплоть до точки выхода (вы никогда не знаете, что какой-нибудь другой фрагмент кода сделает что-то еще для результата , поэтому вы должны отслеживать его до тех пор, пока не существует). Вы делаете это без матер, какая ветвь определяет окончательный результат. Это трудно понять.

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

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
11

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

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

Я недостаточно осведомлен о Java, будет ли вызван «окончательный» блок-код и могут ли финализаторы справиться с ситуацией, требующей, чтобы что-то произошло.

C # Я, конечно, не могу ответить.

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

Функции должны, конечно, не быть такими длинными в первую очередь, и если у вас есть огромный оператор switch, ваш код также, вероятно, также сильно укомплектован.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
7

Ранняя доходность для победы. Они могут казаться уродливыми, но гораздо менее уродливыми, чем большие if обертки, особенно если есть несколько условий для проверки.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
6

Я использую оба.

Если DoSomething - это 3-5 строк кода, тогда код выглядит просто красиво, используя первый метод форматирования.

Но если у него много других строк, то я предпочитаю второй формат. Мне не нравится, когда открывающиеся и закрывающие скобки не находятся на одном экране.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
5

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

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
5

Классическая причина однократного единственного выхода заключается в том, что в противном случае формальная семантика становится неописуемо уродливой в противном случае (по той же причине GOTO считалась вредной).

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

Обычно я минимизирую подход с ранним возвратом.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
5

Это зависит.

Досрочное возвращение, если есть какое-то очевидное условие тупика, которое нужно проверить сразу, что сделает работу остальной функции бессмысленной. *

Установите Retval + single return, если функция более сложна и может иметь несколько точек выхода в противном случае (проблема чтения).

* Это часто может указывать на проблему с дизайном. Если вы обнаружите, что многие ваши методы должны проверять какое-либо внешнее /параметрическое состояние или такие, прежде чем запускать остальную часть кода, это, вероятно, то, что должно обрабатываться вызывающим.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
2

Используйте

В книге Дона Кнута о GOTO, которую я прочитал, он дает повод для того, чтобы всегда иметь наиболее вероятное условие, которое было первым в заявлении if. В предположении, что это все еще разумная идея (а не одно из чистого рассмотрения скорости эпохи). Я бы сказал, что ранние возвращения не являются хорошей практикой программирования, особенно учитывая тот факт, что они чаще всего используются для обработки ошибок, если только ваш код с большей вероятностью не сработает, чем не сработает :-)

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

Delphi Specific ...

Я считаю, что это хорошая практика программирования для программистов Delphi, хотя у меня нет никаких доказательств. Pre-D2009, у нас нет атомного способа вернуть значение, у нас есть exit; и result := foo;, или мы можем просто выбросить исключения.

Если вам пришлось подставить

 if (true) {
 return foo;
} 

для

 if true then 
begin
  result := foo; 
  exit; 
end;

вам может просто поспать, увидев это в верхней части каждой из ваших функций и предпочитая

 if false then 
begin
  result := bar;

   ... 
end
else
   result := foo;

и просто exit вообще.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
1

Я согласен со следующим утверждением:

  

Я лично поклонник статей охраны   (второй пример), поскольку он уменьшает   отступом функции. Некоторые люди   им не нравятся, потому что это приводит к   множественные точки возврата из   функции, но я думаю, что это яснее   с ними.

Взято из этого вопроса в stackoverflow .

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
1

Я использую ранние возвращения почти исключительно в эти дни, до крайности. Я пишу это

 self = [super init];

if (self != nil)
{
    // your code here
}

return self;

а

 self = [super init];
if (!self)
    return;

// your code here

return self;

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

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
1

Я бы предпочел написать:

 if(someCondition)
{
    SomeFunction();
}
ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
0

Условия сверху называются «предварительными условиями». Помещая if(!precond) return;, вы визуально перечисляете все предварительные условия.

Использование большого блока «if-else» может увеличить накладные расходы (я забыл цитату о 3-уровневых отступов).

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
0

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

Мне не нравится, как обработка ошибок удаляется от проверки.

 if not error A
  if not error B
    if not error C
      // do something
    else handle error C
  else handle error B
else handle error A

Я предпочитаю это:

 if error A
  handle error A; return
if error B
  handle error B; return
if error C
  handle error C; return

// do something
ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
-1

Я предпочитаю сохранять, если инструкции небольшие.

Итак, выбирая между:

 if condition:
   line1
   line2
    ...
   line-n

и

 if not condition: return

line1
line2
 ...
line-n

Я бы выбрал то, что вы назвали «ранним возвратом».

Имейте в виду, меня не волнуют ранние возвращения или что-то еще, мне просто очень нравится упрощать код, сокращать тела операторов if и т. д.

Вложенные символы if и for и while horrible , избегайте их любой ценой.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
-2

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

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57
-2

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

В некоторых проверенных условиях вы можете реализовать аспекты этих проверок, если используете AOP.

ответил Alexander 30 Jpm1000000pmFri, 30 Jan 2015 15:43:57 +030015 2015, 15:43:57

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132