假设我有这样的伪代码:

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语句可以以某种方式使用吗?


当前回答

在某些特殊情况下,虚拟继承树和虚拟方法调用可以处理决策树逻辑。

objectp -> DoTheRightStep();

我遇到过这种情况,它就像魔杖一样有效。 当然,如果你的ConditionX可以始终如一地翻译成“object Is A”条件,这是有意义的。

其他回答

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

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(你的第一个变体)或者想要跳出“函数的一部分”通常意味着你确实需要一个额外的函数。

在c++中(这个问题在C和c++中都有标记),如果你不能改变函数来使用异常,你仍然可以使用异常机制,如果你写一个像这样的小助手函数

struct function_failed {};
void attempt(bool retval)
{
  if (!retval)
    throw function_failed(); // or a more specific exception class
}

然后你的代码可以如下所示:

try
{
  attempt(executeStepA());
  attempt(executeStepB());
  attempt(executeStepC());
}
catch (function_failed)
{
  // -- this block intentionally left empty --
}

executeThisFunctionInAnyCase();

如果你喜欢花哨的语法,你可以通过显式强制转换来让它工作:

struct function_failed {};
struct attempt
{
  attempt(bool retval)
  {
    if (!retval)
      throw function_failed();
  }
};

然后您可以将代码编写为

try
{
  (attempt) executeStepA();
  (attempt) executeStepB();
  (attempt) executeStepC();
}
catch (function_failed)
{
  // -- this block intentionally left empty --
}

executeThisFunctionInAnyCase();

你只要这样做。

coverConditions();
executeThisFunctionInAnyCase();

function coverConditions()
 {
 bool conditionA = executeStepA();
 if (!conditionA) return;
 bool conditionB = executeStepB();
 if (!conditionB) return;
 bool conditionC = executeStepC();
 if (!conditionC) return;
 }

99乘以100,这是唯一的方法。

永远、永远、永远不要尝试用计算机代码做一些“棘手”的事情。


顺便说一下,我很确定以下是你脑海中实际的解决方案…

continue语句在算法编程中非常重要。(同样,goto语句在算法编程中也很关键。)

在许多编程语言中,你可以这样做:

-(void)_testKode
    {
    NSLog(@"code a");
    NSLog(@"code b");
    NSLog(@"code c\n");
    
    int x = 69;
    
    {
    
    if ( x == 13 )
        {
        NSLog(@"code d---\n");
        continue;
        }
    
    if ( x == 69 )
        {
        NSLog(@"code e---\n");
        continue;
        }
    
    if ( x == 13 )
        {
        NSLog(@"code f---\n");
        continue;
        }
    
    }
    
    NSLog(@"code g");
    }

(首先要注意:像这个例子一样的裸块是编写漂亮代码的关键和重要部分,特别是如果你在处理“算法”编程。)

再说一遍,你脑子里就是这么想的,对吧?这是很漂亮的写法,所以你有很好的直觉。

然而,不幸的是,在objective-c的当前版本中(对不起,我不知道Swift)有一个可笑的功能,它检查封闭的块是否是一个循环。

下面是你如何解决这个问题的方法……

-(void)_testKode
    {
    NSLog(@"code a");
    NSLog(@"code b");
    NSLog(@"code c\n");
    
    int x = 69;
    
    do{
    
    if ( x == 13 )
        {
        NSLog(@"code d---\n");
        continue;
        }
    
    if ( x == 69 )
        {
        NSLog(@"code e---\n");
        continue;
        }
    
    if ( x == 13 )
        {
        NSLog(@"code f---\n");
        continue;
        }
    
    }while(false);
    
    NSLog(@"code g");
    }

所以不要忘记…

do {} while(false);

只是意味着“做这个块一次”。

也就是说,写do{}while(false)完全没有区别;简单地写{}。

这现在工作完美,因为你想要…这是输出…

所以,这可能就是你在脑海中看到的算法。你应该试着把脑子里的东西写下来。(尤其是你不清醒的时候,因为那个时候你的美就出来了!:))

在“算法”项目中,这种情况经常发生,在objective-c中,我们总是有一个宏…

#define RUNONCE while(false)

... 然后你可以这样做…

-(void)_testKode
    {
    NSLog(@"code a");
    int x = 69;
    
    do{
    if ( x == 13 )
        {
        NSLog(@"code d---\n");
        continue;
        }
    if ( x == 69 )
        {
        NSLog(@"code e---\n");
        continue;
        }
    if ( x == 13 )
        {
        NSLog(@"code f---\n");
        continue;
        }
    }RUNONCE
    
    NSLog(@"code g");
    }

有两点:

首先,尽管objective-c检查continue语句所在的块类型很愚蠢,但“对抗它”很麻烦。所以这是一个艰难的决定。

第二,在这个例子中,你是否应该缩进那个block?这样的问题会让我失眠,所以我不能给你建议。

希望能有所帮助。

在c++中,实际上有一种方法可以延迟操作:使用对象的析构函数。

假设你可以访问c++ 11:

class Defer {
public:
    Defer(std::function<void()> f): f_(std::move(f)) {}
    ~Defer() { if (f_) { f_(); } }

    void cancel() { f_ = std::function<void()>(); }

private:
    Defer(Defer const&) = delete;
    Defer& operator=(Defer const&) = delete;

    std::function<void()> f_;
}; // class Defer

然后使用这个工具:

int foo() {
    Defer const defer{&executeThisFunctionInAnyCase}; // or a lambda

    // ...

    if (!executeA()) { return 1; }

    // ...

    if (!executeB()) { return 2; }

    // ...

    if (!executeC()) { return 3; }

    // ...

    return 4;
} // foo

假设你不需要单独的条件变量,反转测试并使用else-falthrough作为“ok”路径,将允许你获得更垂直的if/else语句集:

bool failed = false;

// keep going if we don't fail
if (failed = !executeStepA())      {}
else if (failed = !executeStepB()) {}
else if (failed = !executeStepC()) {}
else if (failed = !executeStepD()) {}

runThisFunctionInAnyCase();

省略失败的变量使代码在我看来有点太晦涩了。

在里面声明变量就可以了,不用担心= vs ==。

// keep going if we don't fail
if (bool failA = !executeStepA())      {}
else if (bool failB = !executeStepB()) {}
else if (bool failC = !executeStepC()) {}
else if (bool failD = !executeStepD()) {}
else {
     // success !
}

runThisFunctionInAnyCase();

这很模糊,但很紧凑:

// keep going if we don't fail
if (!executeStepA())      {}
else if (!executeStepB()) {}
else if (!executeStepC()) {}
else if (!executeStepD()) {}
else { /* success */ }

runThisFunctionInAnyCase();