假设我有这样的伪代码:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}

executeThisFunctionInAnyCase();

函数executeStepX当且仅当前一个成功时执行。 在任何情况下,executeThisFunctionInAnyCase函数都应该在最后被调用。 我在编程方面是一个新手,所以很抱歉提出一个非常基本的问题:有没有一种方法(例如在C/ c++中)以代码易读性为代价,避免长if链产生那种“金字塔式代码”?

我知道如果我们可以跳过executeThisFunctionInAnyCase函数调用,代码可以简化为:

bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;

但是约束是executeThisFunctionInAnyCase函数调用。 break语句可以以某种方式使用吗?


当前回答

break语句可以以某种方式使用吗?

也许不是最好的解决办法,但你可以把你的陈述变成一种方式。While(0)循环并使用break语句而不是return。

其他回答

在这种情况下,老式的C程序员使用goto。这是goto的一种用法,实际上是Linux样式指南鼓励的,它被称为集中函数exit:

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanup;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    executeThisFunctionInAnyCase();
    return result;
}

有些人使用goto的方法是将body包装成一个循环并将其断开,但实际上这两种方法做的是同一件事。如果你只在executeStepA()成功时才需要一些其他的清理,那么goto方法会更好:

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanupPart;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    innerCleanup();
cleanupPart:
    executeThisFunctionInAnyCase();
    return result;
}

使用循环方法,在这种情况下,您将得到两级循环。

这看起来像一个状态机,这很方便,因为您可以使用状态模式轻松实现它。

在Java中,它看起来像这样:

interface StepState{
public StepState performStep();
}

实现如下所示:

class StepA implements StepState{ 
    public StepState performStep()
     {
         performAction();
         if(condition) return new StepB()
         else return null;
     }
}

等等。然后你可以将大if条件替换为:

Step toDo = new StepA();
while(toDo != null)
      toDo = toDo.performStep();
executeThisFunctionInAnyCase();

只是一个边注;如果if作用域总是导致返回(或循环中断),则不要使用else语句。这可以节省大量的缩进。

另一种解决方案是通过宏hack定义习语。

 #define block for(int block = 0; !block; block++)

现在,“block”可以用break退出,与for(;;)和while()循环的方式相同。例子:

int main(void) {

    block {
       if (conditionA) {
          // Do stuff A...
          break; 
       }
       if (conditionB) {
          // Do stuff B...
          break; 
       }
       if (conditionC) {
          // Do stuff C...
          break; 
       }
       else {
         // Do default stuff...
       }
    } /* End of "block" statement */
    /* --->   The "break" sentences jump here */

    return 0;
} 

尽管使用了“for(;;)”结构,但“block”语句只执行了一次。 这些“块”可以用断句退出。 因此,if else if else if…避免使用句子。 最多,最后一个else可以挂在“块”的末尾,以处理“默认”情况。

该技术旨在避免典型的和丑陋的做{…} while(0)方法。 在宏块中,它定义了一个同样名为block的变量,该变量以这样一种方式定义,即恰好执行了一次for迭代。根据宏的替换规则,宏块定义中的标识符块不会被递归替换,因此block成为程序员无法访问的标识符,但在内部可以很好地控制for(;;)循环的“隐藏”。

此外:这些“块”可以嵌套,因为隐藏变量int块将有不同的作用域。

只需使用一个额外的函数来让你的第二个版本工作:

void foo()
{
  bool conditionA = executeStepA();
  if (!conditionA) return;

  bool conditionB = executeStepB();
  if (!conditionB) return;

  bool conditionC = executeStepC();
  if (!conditionC) return;
}

void bar()
{
  foo();
  executeThisFunctionInAnyCase();
}

使用深度嵌套的if(你的第一个变体)或者想要跳出“函数的一部分”通常意味着你确实需要一个额外的函数。