在IF块中放置什么,在ELSE块中放置什么?
这是一个次要的样式问题,但是我们添加到代码中的每一点可读性都很重要。
因此,如果我们有:
if (condition) then { // do stuff } else { // do other stuff }
我们如何确定像这样更好还是这样:
if (!condition) then { // do other stuff { else { // do stuff }
我的试探法是:
- 保持病情积极(阅读时无需费神)
- 将最常见的路径放入第一块
解决方案
我喜欢第一个。条件应该尽可能简单,并且应该很明显,这比条件和!condition更简单。
我更喜欢将最常见的路径放在第一位,并且我坚信减少嵌套的做法,因此我会尽可能地打破,继续或者返回而不是费劲。我通常更喜欢测试积极的条件,或者将消极的条件颠倒[和命名]为积极的条件。
if (condition) return; DoSomething();
我发现通过大幅度减少其他代码的使用,我的代码更易读和可维护,当我不得不使用其他代码时,它几乎总是适合使用更有条理的switch语句。
这取决于你的流量。对于许多功能,我将使用前提条件:
bool MyFunc(variable) { if (variable != something_i_want) return false; // a large block of code // ... return true; }
如果我需要在每种情况下都要做某事,我将使用if(positive_clause){} else {}
格式。
对我来说,这取决于条件,例如:
if (!PreserveData.Checked) { resetfields();}
我倾向于用自己想要的逻辑对自己说话,并将其编码为脑海中很小的声音。
如果代码要检查错误情况,我更喜欢将该代码放在第一位,然后将"成功"代码放在第二位;从概念上讲,这使函数调用及其错误检查代码保持在一起,这对我来说很有意义,因为它们是相关的。例如:
if (!some_function_that_could_fail()) { // Error handling code } else { // Success code }
我同意Oli在可能的情况下使用肯定的if子句。
请永远不要这样做:
if (somePositiveCondition) else { //stuff }
我曾经在我工作过的某个地方经常看到这种情况,并且曾经想知道其中一位编码员是否不了解它是如何工作的...
通常,如果一个明显大于另一个,则将较大的一个设为" if"块。
- 把共同的道路放在首位
- 把消极的king变成积极的(
!full == empty
)
我知道这并不是我们要查找的内容,但是...许多开发人员使用"保护子句",即,否定的" if"语句,该语句会尽快脱离该方法。在这一点上,确实没有"其他"。
例子:
if (blah == false) { return; // perhaps with a message } // do rest of code here...
那里有一些核心的c / c ++ / assembly家伙,他们会告诉我们我们正在破坏CPU! (在许多情况下,处理器倾向于使用" true"语句,并尝试"预取"下一个要做的事情……因此,从理论上讲,任何" false"条件都将冲洗管道并减慢微秒的时间)。
在我看来,我们处于"更好"(更易于理解)的代码胜过微秒CPU时间的地步。
我认为对于单个变量,not运算符就足够简单了,命名问题开始变得更加相关。
切勿命名变量not_X,如果需要,请使用同义词库查找反义词。我看过很多糟糕的代码,例如
if (not_dead) { } else { }
而不是显而易见的
if (alive) { } else { }
然后,我们可以明智地使用(可读性强,无需反转代码块)
if (!alive) { } else { }
如果我们要谈论更多的变量,我认为最好的规则是简化条件。一段时间后,项目趋向于获得以下条件:
if (dead || (!dead && sleeping)) { } else { }
转化为
if (dead || sleeping) { } else { }
始终注意条件如何以及如何简化它们。
如果必须有多个出口点,请将它们放在第一位并使其清楚:
if TerminatingCondition1 then Exit if TerminatingCondition2 then Exit
现在,我们可以继续进行通常的工作:
if NormalThing then DoNormalThing else DoAbnormalThing
两个(矛盾的)教科书名言:
Put the shortest clause of an if/else on top
-艾伦·霍鲁布(Allen Holub),"用绳索绑住自己的脚",第52页
Put the normal case after the if rather than after the else
-史蒂夫·麦康奈尔(Steve McConnell),"代码完成,第二版",p356
软件是知识的捕获。我们正在编码某人关于如何做某事的知识。
该软件应适合该问题的"自然"部分。如有疑问,请问其他人,看看人们的实际言行。
在"常见"案件什么都不做的情况下该怎么办?然后怎样呢
if( common ) { // pass } else { // great big block of exception-handling folderol }
还是你这样做?
if( ! common ) { // great big block of except-handling folderol }
"永远积极"的规则并不是我们真正想要的。我们想看如下规则。
- 总是很自然-读起来应该像英语(或者组织中的通用语言)。
- 在可能的情况下,首先是常见情况-因此它们看起来很常见。
- 尽可能使用正逻辑;否定逻辑可以用在通常这样说的地方,或者是在无所事事的情况下使用。
如果两条路径中的一条非常短(大约1至10行),而另一条更长,则遵循此处提到的Holub规则,并将较短的代码放入if中。这使得在查看代码时更容易在一个屏幕上查看if / else流程。
如果这不可能,那么我将结构简化为尽可能简单的条件。
当我查看数据验证时,我尝试将我的条件设置为"白名单",也就是说,我测试了我将接受的内容:
if DataIsGood() then DoMyNormalStuff else TakeEvasiveAction
而不是相反,它倾向于退化为:
if SomeErrorTest then TakeSomeEvasiveAction else if SomeOtherErrorCondition then CorrectMoreStupidUserProblems else if YetAnotherErrorThatNoOneThoughtOf then DoMoreErrorHandling else DoMyNormalStuff
通常,我们可以使条件为正,而无需在if / else块之间切换。
改变
if (!widget.enabled()) { // more common } else { // less common }
到
if (widget.disabled()) { // more common } else { // less common }
英特尔奔腾分支预测会针对" if"情况预取指令。相反,如果它遵循" else"分支:则刷新指令管道,从而导致停顿。
如果我们非常在意性能,请在" if"子句中添加最可能的结果。
我个人写为
if (expected) { //expected path } else { //fallback other odd case }
我总是把最有可能的放在第一位。
在Perl中,我有一个额外的控制结构来帮助实现这一点。 if的倒数。
unless (alive) { go_to_heaven; } else { say "MEDIC"; }
如果我们同时具有真假条件,那么我将选择正条件,这会减少混乱,总的来说,我认为这会使代码更易于阅读。
另一方面,如果我们使用的是Perl之类的语言,尤其是如果错误条件是错误条件或者最常见的条件,则可以使用"除非"结构,该结构将执行代码块,除非该条件是真实的(即与if相反):
unless ($foo) { $bar; }
我们应该始终将最可能的情况放在首位。除了更具可读性,它还更快。这也适用于switch语句。
关于如何设置if语句,我感到很恐怖。基本上,我是根据我要寻找的内容进行设置的,这导致一切都与众不同。
如果(userinput = null){
explodeViolently();
} 别的 {
实际做事;
}
或者类似的东西
如果(1 + 1 = 2){
做东西;
} 别的 {
explodeViolently();
}
if / else语句的哪一部分实际为我做事是我的坏习惯。
首先,让我们把情况放在一边,最好不要使用"其他"(我希望每个人都同意这种情况确实存在,并确定这种情况可能是一个单独的话题)。
因此,我们假设必须有一个" else"子句。
我认为可读性/可理解性强加了至少三个关键要求或者规则,不幸的是,它们经常相互竞争:
- 第一个块(" if"块)越短,就越容易掌握整个" if-else"结构。当" if"块足够长时,忽略" else"块的存在变得太容易了。
- 当" if"和" else"路径在逻辑上是不对称的(例如"正常处理"与"错误处理")时,在独立的" if-else"构造中,哪个路径是第一路径,哪个路径是第二路径并不重要。 。但是,当有多个彼此相邻的" if-else"构造(包括嵌套),并且所有这些" if-else"构造都具有相同的不对称性时,这时布置这些非对称路径非常重要始终如一。同样,可以全部使用"如果...正常路径... else ...异常路径",或者全部使用"如果...异常路径... else ...正常路径",但是不应该这样是这两个变体的混合体。在所有其他条件相同的情况下,对大多数人来说,将正常道路放在首位可能更自然(我认为这更多是关于心理学而不是美学:-)。
- 以否定开头的表达式通常比没有表达式的可读性/可理解性低。
因此,我们有这三个相互竞争的需求/规则,而真正的问题是:其中哪一个比其他的更为重要。对于Allen Holub来说,规则#1可能是最重要的。对于史蒂夫·麦康奈尔(Steve McConnell),这是规则2. 但是我认为我们真的不能只选择其中一条规则作为一条基德线。
我敢打赌,我们已经在这里猜到了我的个人优先事项(根据我订购上述规则的方式:-)。
我的原因很简单:
- 规则#1是无条件的,无法规避。如果其中一个块太长以至于无法在屏幕上显示-它必须成为" else"块。 (不,机械地创建函数/方法只是减少" if"或者" else"块中的行数不是一个好主意!我假设每个块已经具有逻辑上合理的最小行数。 )
- 规则2涉及很多条件:多个" if-else"构造,所有构造都具有相同的不对称性,等等。因此,它仅在许多情况下不适用。此外,我经常观察到以下有趣的现象:当规则2确实适用并且正确使用时,它实际上与规则1不冲突!例如,每当我有一堆具有"正常与异常"不对称性的" if-else"语句时,所有"异常"路径都比"正常"路径短(反之亦然)。我无法解释这种现象,但是我认为这只是良好的代码组织的标志。换句话说,每当我看到规则#1和#2发生冲突的情况时,我就会开始寻找"代码气味",而且我经常发现一些"代码气味"。重构后-多田!在规则1和规则2之间再无痛苦的选择,:-)
- 最后,规则3的范围最小,因此最不重要。另外,正如其他同事在此所述,通常很容易使用此规则"作弊"(例如,编写" if(disabled),"而不是" if(!enabled)...")。
我希望有人可以对这个作品有所了解。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。