2015-05-04 3 views
11

В моем коде у меня есть, если заявление, которое выглядит как:Сети ИЛИ условия, если заявление

if(someFunction1(a) || someFunction2(b->b1,c) || *d == null || somefunction3(e) > f * g || !e->e1 || ...){ 
    return 0; 
} else { 
    do_something; 
} 

В моем коде с именами реальными переменными и функций являются условиями почти в три линии, и это выглядит очень упускать из вида , Поэтому я решил переписать его в форму:

if(someFunction1(a)){ 
    return 0; 
} else if(someFunction2(b->b1,c)){ 
    return 0; 
} else if(*d == null){ 
    return 0; 
} else if(somefunction3(e) > f * g){ 
    return 0; 
} else if(!e->e1){ 
    return 0; 
} else if(...){ 
    return 0; 
} else{ 
    do_something; 
} 

Есть ли аргументы, почему я не должен этого делать?

+0

Возможный дубликат [Как отложить длинные условные выражения для операторов «если»?] (Http://stackoverflow.com/questions/1059166/how-to-indent-long-conditionals-for-if-statements) – moooeeeep

+0

Явно этот вопрос граничит с вопросом индивидуального стиля (в первую очередь мнения). – moooeeeep

+0

Это на грани прежде всего основанных на мнениях, но я думаю, что этот вопрос достаточно узкий для формата SO. Кроме того, я думаю, что программистам нужно время от времени выпускать эти вещи, как мы можем сказать по количеству голосов голосов, таких как все. Таким образом, нет необходимости закрывать вопрос, хотя вполне возможно, что это будет субъективная дискуссия. – Lundin

ответ

17

С чисто семантической-синтаксической точки зрения нет никакой принципиальной разницы между ними , Но если читаемость ваше беспокойство, почему бы вам не использовать «datenwolf» стиля форматирования - Я пришел, чтобы развивать этот стиль в течение моих прошлых 5 проектов или так:

if(someFunction1(a) 
|| someFunction2(b->b1,c) 
|| *d == null 
|| somefunction3(e) > f * g 
|| !e->e1 
|| ... 
){ 
    return 0; 
} else { 
    do_something; 
} 

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

+11

«Трубка программа падала через« ... »цепь операций, которая не должна быть сломана» ... И люди все еще смеются надо мной, когда я говорю, что программирование - это искусство ... – Mints97

+0

На стороне записки, вы можете использовать логические логические операторы ('||', '&&') вне условного выражения для реализации такого управления потоком. Однако я категорически не рекомендую это делать, и на самом деле я настоятельно рекомендую объединить все вызовы к нетривиальной функции (т. Е. Функции, которые могут терпеть неудачу) с проверкой ошибок. – datenwolf

+0

Мне бы тоже понравилось (хотя я помещаю «трубку» в правой части выражения), если мне не нужно было размещать обширные комментарии для каждого случая ошибки. В этом случае вам нужно разбить код. – Lundin

3

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

Но эта избыточность не возникает в первой реализации.

Оба варианта аналогичны.

+1

Конечно, было бы тривиально учитывать это, например, 'const int retval = 0;' перед первым 'if', а затем do' return retval; 'по мере необходимости. – unwind

+0

@unwind: Это было бы. Но все же это не так эффективно, потому что есть избыточность. OP расширяет один код линии до почти 15 строк: P –

6

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

bool unnecessary = someFunction1(a) || someFunction2(b->b1,c); 
bool beyondTolerance = somefunction3(e) > f * g; 
bool invalidInput = *d == nullptr || !e->e1; 

if (unnecessary || beyondTolerance || invalidInput) 
    return 0; 
else 
    ... 

Это Мартин Фаулер Decompose Conditional рефакторинга.

+8

Вы должны быть осторожны, если вы это сделаете. Исходный код может основываться на оценке __short-circuit__, которая изменяется в этом коде. – Blastfurnace

+0

Лично я бы не пытался добавить еще большую сложность в уже сложные выражения. – Lundin

0

Вы можете сделать это следующим образом

int not_valid = someFunction1(a) || 
       someFunction2(b->b1,c) || 
       *d == null || 
       somefunction3(e) > f * g || 
       !e->e1 || ...; 

if (!not_valid) 
{ 
    do_something; 
} 

return !not_valid; 

Вместо not_valid вы можете выбрать более подходящее имя. :)

5

Вариант 1:

  • краткость
  • Одна точка выхода, чтобы избежать избыточности оператора возврата.

Вариант 2:

  • Точная точка отказа можно легко диагностировать журналы т.е. могут быть добавлены к каждой ветви, чтобы обнаружить сбой.
2

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


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

Учитывая, что это не очень хорошая идея написать код как один оператор вообще, потому что если вам придется сжимать комментарии в середине инструкции, код станет беспорядком.

С выше обоснованием, лучшим способом, чтобы написать такие, возможно:

/* comments here */ 
if(someFunction1(a)){ 
    return 0; 
} 

/* comments here */ 
if(someFunction2(b->b1,c)){ 
return 0; 
} 

... 

/* if we got here, then there are no errors */ 
do_something(); 

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

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

Смежные вопросы