2010-03-06 88 views
8

多年的编码带来我相信,努力实现这种如果有条件编码:(C语言表现出来,但它的相关的几乎任何语言)如果条件最好的编码习惯是什么?

if(a <= 0) 
     return false; 
if(strlen(str) <= a) 
     return false; 
if(str[a] == NULL) 
     return false; 
return true; 

我认为这是比更可读接下来的编码样本,尤其是在广大的条件:

if(a >0) 
{ 
    if(strlen(str) > a) 
    { 
      if(str[a] != NULL) 
      { 
       return true; 
      } 
     } 
    } 

而上的代码是更具可读性,大状况下,你可能会发现自己关闭如此多的“}”,最后的代码,我认为这是编译成性能更好的代码。

你认为哪一个最好用?

(在这个例子的代码只是为了证明不采取它的字面)

+1

第二个将是可读格式。你可以在&&条件中有这三个表达式。所以,你会只使用一个条件。 – Pavunkumar 2010-03-06 06:12:15

+1

也许我的编码样本不是这个问题的“正确”样本。我知道你可以把它放在一条线上。但我试图询问关于编码习惯本身。 – aviv 2010-03-06 07:15:10

回答

2

如果您遵循Design By Contract设计,那么您在输入功能时必须满足前提条件。虽然在某些情况下可以证明某些先决条件已经满足,但在这些情况下,测试不是必需的,我们假设在这里测试是必要的。在这些假设下,功能合同式的前提条件必须在其他任何事情都可以完成之前进行检查,并且检查应该被认为与功能应该做的实际工作无关。那么它遵循:

  • 试验的先决条件必须在任何其他代码的功能
  • 如果先决条件测试失败,函数应立即返回

返回出现立即确保条件测试与功能的实际主体完全分离,不仅在语义上而且在词汇上都是如此。这样可以轻松查看代码并确定是否遵循功能合同。它还使得在功能合同被修改的情况下稍后添加或删除先决条件变得容易。

示例代码:

// function contract 
// 
// pre-conditions: 
// 
// o bar must not be zero 
// o foo_ptr must not be NULL 
// o foo_ptr must refer to a foo variant of type blue_foo 
// 
// ... 

Foo *foo_blue_init_with_bar(Foo *foo_ptr, int bar, foo_status *status) { 

    // ***** Test Pre-conditions ***** 

    // bar must not be zero 
    if (bar == 0) { 
     if (status != NULL) *status = FOO_STATUS_INVALID_BAR; 
     return NULL; 
    } 

    // foo_ptr must not be NULL 
    if (foo_ptr == NULL) { 
     if (status != NULL) *status = FOO_STATUS_INVALID_FOO_POINTER; 
     return NULL; 
    } 

    // foo_ptr must refer to a foo variant of type blue_foo 
    if (foo_ptr->type != blue_foo) { 
     if (status != NULL) *status = FOO_STATUS_INVALID_FOO_VARIANT; 
     return NULL; 
    } 

    // ***** Actual Work Goes Here ***** 

    ... 

} // end foo_blue_init_with_bar 

在另一方面,如果你不遵守契约式设计,那么它可以算得上是个人喜好的问题。

5

我个人一起去的第一部分。 尽早退回。

+0

我会想象一个体面的编译器会优化第二种情况,以便它实际上早日返回。没有? – amn 2010-03-06 15:43:05

+0

谁在这个答案中说了关于编译器优化的任何事情? – Anurag 2010-03-06 17:44:36

0

我选择第二个希望会更好,因为它更好地描述了逻辑,常用的最佳实践是你最好只在函数内部有一个return语句。

由于性能原因,我不会选择第一个,因为编译器无论如何都会进行优化,我更喜欢可读的代码。

+1

为什么最好的做法是在一个函数中使用1个return语句? – 2010-03-06 06:09:06

+1

这是一个_old_“公理”,在方法中只有一个返回会降低复杂性。这些日子并不常见,但仍然泛泛而谈。 – 2010-03-06 06:10:39

8

问题不是很清楚,在这里。如果我们比较这:

if (c1) return false; 
if (c2) return false; 
if (c3) return false; 
return true; 

有了这个:

if (!c1) { 
    if (!c2) { 
    if (!c3) { 
     return true; 
    } 
    } 
} 
return false; 

然后我会投票给都不是。做到这一点,而不是:

return !c1 && !c2 && !c3; 

如果问题是关于多回报是否是可以接受的,那么这个问题已经讨论过了(见:Should a function have only one return statement

2

第一种方法看起来aestheticly更好,但我不不认为它完全捕捉你想要做的事情。如果所有的条件在逻辑上属于一起,那么把它们放在一个if语句中(我把布尔操作符放在行的开头,以便在测试过程中更容易注释单个条件(从大的SQL WHERE子句挂起) ) :

if(a > 0 
     && strlen(str) > a 
     && str[a] != NULL) 
    { 
     return true; 
    } 

或者,返回一个布尔值时(这是一个特例,从而可能不适用于你的问题):

return (a > 0 
     && strlen(str) > a 
     && str[a] != NULL); 
1

如果条件具有类似或相关的语义,它可能是更好的使用逻辑表达式而不是一堆if s。喜欢的东西

return a > 0 && strlen(str) > a && str[a] != NULL; 

但是如果你有使用if,最好的方法来组织分支经常(如果不总是)取决于if本身的性质。

大部分时间代码中的if都是“不平衡的”:它们或者只有一个分支(没有else),或者其中一个分支是“重量级”,而其他分支是“轻量级”。在这种情况下,首先处理“简单”分支总是更好,然后明确指出该分支的处理已结束。这是通过使用你的第一个变体问题来实现的:检测需要“简单”处理的情况,做到这一点,并立即return(如果你必须离开功能)或做continue(如果你必须进行下一步循环的迭代)。这是立即return(或continue),帮助读者了解,这个分支已经完成,并且不需要再担心它。所以,一个典型的函数看起来如下:一些if s“拦截”简单情况,立即处理它们(如果需要)和return。只有在处理了所有简单化的案例后,通用的“重”处理才开始。像这样组织起来的函数比带有一堆嵌套的函数(比如你的第二个变体)更容易阅读。

有些人可能会认为从函数中间的return或在周期中间的continue违背了“结构化编程”的想法。但不知何故,人们错过了“结构化编程”这个概念从未被用于实际应用的事实。不,早期的“return”原则(或“continue早期”)明显提高了代码的可读性,因为它明确强调了该分支的处理已结束的事实。在“结构化”if的情况下,这样的事情就不那么明显了。

重新开始:避免嵌套if s。他们很难阅读。避免“不平衡”if s。他们也很难阅读。首选“扁平”分支风格,首先处理简单案例,并立即通过明确的returncontinue完成处理。

0

第一种方法的主要原因是缩进保持在理智的水平。超过两个级别的任何事情开始变得难以管理。就个人而言,我尝试在大多数时间内不超过方法内的单个缩进级别。

但是,对于我而言,至少对于我来说,第二种选择更清晰,因为逻辑看起来很简单。当满足所有三个条件时,我们返回true。我倾向于将每个布尔结果存储到一个变量中,该变量的名称对于传递的值有意义,并返回它们的AND值。

isPositive = a > 0; 
isStringLonger = str.length() > a; 
isCharacterNonNull = str[a] != NULL; 

return isPositive && isStringLonger && isCharacterNonNull; 

我刚刚根据你的例子做了名字,所以他们看起来像垃圾,但重点是他们不应该。

或者,当这三个变量看起来很多时,我会在返回之前将它们合并成一个变量。

isValidString = isPositive && isStringLonger && isCharacterNonNull; 
return isValidString; 

就多重返回语句而言,我发现Ruby为大多数语句添加后缀的方式非常干净和可读。

return false if a <= 0 
return false if str.length() <= a 
return false if !str[a].nil? 
return true 
0

你的两个样本做不同的事情(见下面的代码)。我宁愿第二,如果它是这样写下面的(也许除了用更少的括号内。

if((a>0) && (strlen(str) > a) && (str[a] != NULL)) 
{ 
    return true; 
} 

或写的

return ((a>0) && (strlen(str) > a) && (str[a] != NULL)) 

要回答你的问题。我更喜欢第一(除上面的代码是正确的),我总是更喜欢

  1. 更少tabbing。我更喜欢一切尽可能留下你的第二个例子中断(但不是我的)
  2. 如果可能,返回顶部如果(cond)返回等等; else {code(); }
  3. 在顶部和较长的代码短码在底部

    如果(COND) { 码(); } else if(cond2) { code(); code(); } else { code(); code(); code(); }