我对良好的编码习惯有疑问。我理解执行<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<input value="submit" type="submit">
</form>
和多个if-else if
之间的区别(即,当if
中满足条件时,将跳过其余检查)。我在这些方面找到了一段代码:
if-else if
据我所知,如果A == 5,此代码不会检查B == 7.代码有效,这意味着B只有7,如果A不是5,但我认为这只是等待中断当代码改变时。我会做的是:
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
}
我的问题是,当我有多个依赖于不同的独占变量的独占案例时,解决流量控制的最佳方法是什么?我的印象是第一个代码(使用else ifs)很大程度上取决于其他代码片段的工作,而其他方面的更改可能会破坏它。第二个看起来有点笨拙。一个开关可能是第三个选项,但我需要创建另一个结构来保持大小写和逻辑来分配它的值,我认为它会有点笨拙和反直觉。
答案 0 :(得分:2)
您询问了“独家”案例,但条件A == 5
和B == 7
的问题在于它们不独占;他们是独立的。
为了完全普遍,你可能需要测试和处理所有四种情况:
if(A == 5) {
if(B == 7) {
/* case 1 */
} else {
/* case 2 */
}
} else {
if(B == 7) {
/* case 3 */
} else {
/* case 4 */
}
}
这是臭名昭着的“浓密”if / else块。这是臭名昭着的,因为它几乎不可能立即让读者无法遵循,特别是如果涉及案件,或引入更多层次。 (我认为大多数风格指南会告诉你永远不要使用3级或更高级别的if / else树。我当然会这么说。)
我偶尔会使用这两种选择:
(1)完全解耦案件:
if(A == 5 && B == 7) {
/* case 1 */
} else if(A == 5 && B != 7) {
/* case 2 */
} else if(A != 5 && B == 7) {
/* case 3 */
} else if(A != 5 && B != 7) {
/* case 4 */
} else {
/* can't happen */
}
这里的要点是让后来的读者最清楚地知道哪些情况与案例1,2,3和4一致。因此,您最好明确列出最后一个else if(A != 5 && B != 7)
案例(正如我所示),尽管到那时它基本上是一个“别的”。
(2)转换“两级”开关。我不能说这是一种常见的技巧;它有一种“太聪明”的味道,但它的健壮性和可读性:
#define PAIR(b1, b2) (((b1) << 8) | (b2))
switch(PAIR(A == 5), (B == 7)) {
case PAIR(TRUE, TRUE):
/* case 1 */
break;
case PAIR(TRUE, FALSE):
/* case 2 */
break;
case PAIR(FALSE, TRUE):
/* case 3 */
break;
case PAIR(FALSE, FALSE):
/* case 4 */
break;
}
当条件为A == 5
和B == 7
时,我不建议这样做,因为当你在开关中瘫痪时,“TRUE”和“FALSE”的含义并不明显,但有时候,这种事情可以干净利落地阅读。它也可以干净地适应3层或更多级别的嵌套,不像“浓密”的if / else树,正如我所说的那样,这是非常难以理解的。
答案 1 :(得分:1)
我想您知道,这两段代码并不相同。 (它们等同于 IF 它们都包含“返回或继续或中断”,这使得问题更有趣,但这是一个不同的答案。)
一般来说,你选择哪一个(或你如何选择重写它)必须完全依赖你希望程序做什么。
写作时
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
}
除非 do_something_else
不等于5,否则你还要说A
。这可能就是你想要的,或者它可能是一个bug 。如果你想在没有else
的情况下达到相同的效果,它必须如下所示:
if (A == 5) {
do_something();
}
if (A != 5 && B == 7) {
do_something_else();
}
另一方面,您在问题中写的第二段代码有可能同时执行do_something
和 do_something_else
。
一般来说,如果if / else链中的所有条件都在相同条件下进行变化,而不是涉及A
和{{1}的一些异常混合,那么它是最好的(最清晰且最不容易混淆) }}
当替代品真正且刻意排除时,您使用if / else块,并且当您想强调这一事实时。您可以选择使用单独的B
块(不与if
链接),当替代品不是排他性的,或者只是巧合或意外排除时。例如,我故意编写像
else
当两个事物彼此无关时,我可能会这样做,这意味着在程序逻辑的某些未来版本中,它们可能根本不是排他性的。或者,我可能会这样做,如果if(A == 5) {
do_something();
}
if(A != 5) {
do_some_unrelated_thing();
}
不是一个单一的,但是是一个冗长的,精心设计的块,最后我担心读者可能不记得我们为什么或不做一些东西,另一方面,我们可能想做别的事情。出于类似的原因,我偶尔会写
do_something
在这种情况下,要完成的两件事情彼此无关,而且这样做的原因可能会有所不同。
答案 2 :(得分:1)
最强大的编程方式,
同时避免假设A==5
或B==7
要考虑所有四种情况:
if ((A == 5) && (B == 7))
{
do_somethingAB();
/* or */
do_somethingA();
do_somethingB();
} else if (A == 5)
{
do_somethingA();
} else if (B == 7)
{
do_somethingB();
} else
{
do_somethingNeither();
/* or
do nothing */
}
答案 3 :(得分:1)
[这是我的第三个答案。事实上,我一直在误读你的问题,而没有理解你所提出的要点,这表明我可能根本就不应该回答。]
我认为您提出的基本要点涉及案例独立的情况,但您获得else
的效果由于每个子句都包含一个控制流语句,其中包括:break
,或continue
,或return
,或类似这一点。
在这种特定情况下,我今天的偏好是不使用else
。我们写的时候
if(A == 5) {
do_something();
return or continue or break;
}
if(B == 7) {
do_something_else();
return or continue or break;
}
很明显,这两个条件之间没有任何关系,除了这两个条件之外,他们都做了一些事情来完成&#34;完成&#34;完成子任务,并留下负责执行该子任务的代码块。
当我们分别写两个案例(没有其他)时,我们不仅明确表示他们是独立的,而且可以重新排序,或者可以在他们之间引入另一个案例,等等。 / p>
但是,再次,可以重新排序?两个案例A == 5
和B == 7
两者都是真的有多大可能性?在这种情况下,do_something
与do_something_else
相比,有多重要?如果不能重新排序这两种情况,如果首先测试B
并且可能do_something_else
进行测试是错误的,我认为明确的else
是优选的,以便将两者联系起来将案件放在一起,并使A
首先被测试的要求更加明确。
与任何风格问题一样,支持和反对这种事情的论据最终都是非常主观的。你不可能以某种方式找到一个令人难以置信的令人信服的答案。
答案 4 :(得分:1)
One way to handle this is to use a do { ... } while (0);
technique.
Here is your original code:
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
}
Doing else if
on the same line is [IMO] a bit of a hack because it hides the true indentation:
if (A == 5) {
do_something();
}
else
if (B == 7) {
do_something_else();
}
Using the aformentioned technique, which I've used quite a lot is:
do {
if (A == 5) {
do_something();
break;
}
if (B == 7) {
do_something_else();
break;
}
} while (0);
This becomes even more evident when we increase the number of levels in the if/else ladder:
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
} else if (C == 9) {
do_something_else_again();
} else if (D == 3) {
do_something_for_D();
}
Once again, this is indented to:
if (A == 5) {
do_something();
}
else
if (B == 7) {
do_something_else();
}
else
if (C == 9) {
do_something_else_again();
}
else
if (D == 3) {
do_something_for_D();
}
Using the do/while/0
block, we get something that is simpler/cleaner:
do {
if (A == 5) {
do_something();
break;
}
if (B == 7) {
do_something_else();
break;
}
if (C == 9) {
do_something_else_again();
break;
}
if (D == 3) {
do_something_for_D();
break;
}
} while (0);
Note: I've been programming in c
for 35+ years, and I've yet to find a case where a more standard use of do/while
(e.g. do { ... } while (<cond>)
) can't be replaced more cleanly/effectively with either a standard for
or while
loop. Some languages don't even have a do/while
loop. Thus, I consider the do
loop to be available for reuse.
Another use of do/while/0
is to allow things defined by a preprocessor macro to appear as a single block:
#define ABORTME(msg_) \
do { \
printf(stderr,"ABORT: %s (at line %d)\n",msg_,__LINE__); \
dump_some_state_data(); \
exit(1); \
} while (0)
if (some_error_condition)
ABORTME("some_error_condition");