假设我有这样的伪代码:
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语句可以以某种方式使用吗?
假设所需的代码是我目前看到的:
bool conditionA = executeStepA();
if (conditionA){
bool conditionB = executeStepB();
if (conditionB){
bool conditionC = executeStepC();
if (conditionC){
...
}
}
}
executeThisFunctionInAnyCase();
我想说,正确的方法,因为它是最容易阅读和最容易维护的,应该有更少的缩进级别,这是(目前)这个问题的目的。
// Pre-declare the variables for the conditions
bool conditionA = false;
bool conditionB = false;
bool conditionC = false;
// Execute each step only if the pre-conditions are met
conditionA = executeStepA();
if (conditionA)
conditionB = executeStepB();
if (conditionB)
conditionC = executeStepC();
if (conditionC) {
...
}
// Unconditionally execute the 'cleanup' part.
executeThisFunctionInAnyCase();
这避免了对gotos、异常、dummy while循环或其他困难结构的任何需求,只需继续手头的简单工作。
假循环已经提到了,但我没有看到下面的技巧在给出的答案:你可以使用一个do{/*…*/} while(evalates_to_zero ());实现一个双向早出中断。使用break终止循环而不计算条件语句,而使用continue将计算条件语句。
你可以使用它,如果你有两种类型的终结,其中一条路径必须比另一条路径做更多的工作:
#include <stdio.h>
#include <ctype.h>
int finalize(char ch)
{
fprintf(stdout, "read a character: %c\n", (char)toupper(ch));
return 0;
}
int main(int argc, char *argv[])
{
int ch;
do {
ch = fgetc(stdin);
if( isdigit(ch) ) {
fprintf(stderr, "read a digit (%c): aborting!\n", (char)ch);
break;
}
if( isalpha(ch) ) {
continue;
}
fprintf(stdout, "thank you\n");
} while( finalize(ch) );
return 0;
}
执行此命令会得到以下会话协议:
dw@narfi ~/misc/test/fakeloopbreak $ ./fakeloopbreak
-
thank you
read a character: -
dw@narfi ~/misc/test/fakeloopbreak $ ./fakeloopbreak
a
read a character: A
dw@narfi ~/misc/test/fakeloopbreak $ ./fakeloopbreak
1
read a digit (1): aborting!
在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();
有几个回答暗示了我看到并使用过很多次的模式,尤其是在网络编程中。在网络堆栈中,经常有很长的请求序列,其中任何一个都可能失败并停止进程。
常见的模式是使用do {} while (false);
我使用宏while(false)使它做{}一次;常见的模式是:
do
{
bool conditionA = executeStepA();
if (! conditionA) break;
bool conditionB = executeStepB();
if (! conditionB) break;
// etc.
} while (false);
这种模式相对容易阅读,并且允许使用能够正确销毁的对象,还避免了多次返回,从而使步进和调试更容易一些。