如何摆脱开关内的循环?
我正在写一些看起来像这样的代码:
while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: break; // **HERE, I want to break out of the loop itself** } }
有没有直接的方法来做到这一点?
我知道我可以使用一个标志,并通过在切换之后放置一个条件中断来从循环中断开。 我只想知道C ++是否已经有一些构造。
前提
以下代码应该被认为是不好的forms,不pipe语言或所需function如何:
while( true ) { }
支持参数
while( true )
循环是不好的forms,因为它:
- 打破一个while循环的隐含合约。
- while循环声明应明确说明唯一的退出条件。
- 意味着它永远循环。
- 必须阅读循环中的代码才能理解终止子句。
- 循环重复的循环将阻止用户从程序中终止程序。
- 效率低下
- 有多个循环终止条件,包括检查“真”。
- 容易出错。
- 无法轻松确定在哪个位置放置代码,这些代码将始终为每次迭代执行。
- 导致不必要的复杂的代码。
替代“转到”
下面的代码是更好的forms:
while( isValidState() ) { execute(); } bool isValidState() { return msg->state != DONE; }
优点
没有标志。 没有goto
没有例外。 容易改变。 易于阅读。 易于修复。 另外代码:
- 从循环本身中分离循环工作负载的知识。
- 允许维护代码的人轻松地扩展function。
- 允许在一个地方分配多个终止条件。
- 将终止子句从要执行的代码中分离出来。
- 对核电厂更安全。 😉
第二点很重要。 不知道代码是如何工作的,如果有人问我做主循环让其他线程(或进程)有一些CPU时间,那么有两个解决scheme:
选项1
快速插入暂停:
while( isValidState() ) { execute(); sleep(); }
选项#2
覆盖执行:
void execute() { super->execute(); sleep(); }
这个代码比带embedded式switch
的循环更简单(因此更容易阅读)。 isValidState
方法只应该确定循环是否应该继续。 该方法的主力应该被抽象成execute
方法,它允许子类覆盖默认行为(一个困难的任务使用embedded式switch
和goto
)。
Python示例
对比在StackOverflow上发布的以下答案(对于Python问题):
- 永远循环。
- 要求用户input他们的select。
- 如果用户的input是“重新启动”,则继续循环。
- 否则,永远停止循环。
- 结束。
码
while True: choice = raw_input('What do you want? ') if choice == 'restart': continue else: break print 'Break!'
与:
- 初始化用户的select。
- 循环,而用户的select是单词“重新启动”。
- 要求用户input他们的select。
- 结束。
码
choice = 'restart'; while choice == 'restart': choice = raw_input('What do you want? ') print 'Break!'
在这里, while True
导致误导和过于复杂的代码。
你可以使用goto
。
while ( ... ) { switch( ... ) { case ...: goto exit_loop; } } exit_loop: ;
另一种解决方法是使用关键字continue
和break
,即:
for (;;) { switch(msg->state) { case MSGTYPE // code continue; // continue with loop case DONE: break; } break; }
使用continue
语句完成您希望循环继续的每个大小写标签,并使用break
语句完成应该终止循环的大小写标签。
当然这个解决scheme只有在switch语句后没有额外的代码才能执行。
一个干净利落的方法就是把这个function变成一个function:
int yourfunc() { while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: return; } } }
可选地(但是“坏习惯”):如已经暗示的那样,你可以使用goto,或者在交换机内部抛出exception。
AFAIK在C ++中没有“双重中断”或类似的构造。 最接近的将是一个goto
– 虽然它的名字有一个不好的内涵,但是它存在于语言中是有原因的 – 只要谨慎和谨慎地使用它,这是一个可行的select。
你可以把你的开关放到一个单独的函数中,像这样:
bool myswitchfunction() { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: return false; // **HERE, I want to break out of the loop itself** } return true; } while(myswitchfunction()) ;
即使你不喜欢转到,也不要使用exception来退出循环。 下面的例子显示了它可能是多么的丑陋:
try { while ( ... ) { switch( ... ) { case ...: throw 777; // I'm afraid of goto } } } catch ( int ) { }
我会在这个答案中使用goto
。 在这种情况下, goto
将使代码更清晰,然后再select其他选项。 我希望这个问题会有所帮助。
但我认为使用goto
是唯一的select,因为stringwhile(true)
。 你应该考虑重构你的循环。 我会假设以下解决scheme:
bool end_loop = false; while ( !end_loop ) { switch( msg->state ) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: end_loop = true; break; } }
甚至以下:
while ( msg->state != DONE ) { switch( msg->state ) { case MSGTYPE: // ... break; // ... more stuff ... }
在这种情况下,没有C ++构造来打破循环。
要么使用一个标志来中断循环,要么(如果合适的话)将你的代码提取到一个函数中并使用return
。
你可能会使用goto,但是我宁愿设置一个停止循环的标志。 然后跳出开关。
为什么不修复你的while循环中的条件,导致问题消失?
while(msg->state != DONE) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: // We can't get here, but for completeness we list it. break; // **HERE, I want to break out of the loop itself** } }
我认为;
while(msg->state != mExit) { switch(msg->state) { case MSGTYPE: // ... break; case DONE: // .. // .. msg->state =mExit; break; } } if (msg->state ==mExit) msg->state =DONE;
最简单的方法是在做SWITCH之前先做一个简单的IF,然后IFtesting你退出循环的条件……….尽可能简单
C ++中的break
关键字只能终止最嵌套的迭代或switch
语句。 因此,你不能在switch
语句中直接跳出while (true)
循环; 但是你可以使用下面的代码,我认为这是一个很好的模式,这种types的问题:
for (; msg->state != DONE; msg = next_message()) { switch (msg->state) { case MSGTYPE: //... break; //... } }
如果你需要在msg->state
等于DONE
时做某些事情(比如运行一个清理例程),那么在for
循环之后立即放置该代码; 即如果您目前有:
while (true) { switch (msg->state) { case MSGTYPE: //... break; //... case DONE: do_cleanup(); break; } if (msg->state == DONE) break; msg = next_message(); }
然后改用:
for (; msg->state != DONE; msg = next_message()) { switch (msg->state) { case MSGTYPE: //... break; //... } } assert(msg->state == DONE); do_cleanup();
这令我感到惊讶,这是多么简单,这是考虑到解释的深度…这是所有你需要的…
bool imLoopin = true; while(imLoopin) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: imLoopin = false; break; } }
大声笑!! 真! 这就是你所需要的! 一个额外的variables!
while(MyCondition) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: MyCondition=false; // just add this code and you will be out of loop. break; // **HERE, you want to break out of the loop itself** } }
我得到了同样的问题,并使用一个标志解决。
bool flag = false; while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: flag = true; // **HERE, I want to break out of the loop itself** } if(flag) break; }
不,C ++没有这样的构造,因为关键字“break”已经保留用于退出切换块。 另外一个do..while()与退出标志可能就足够了。
do { switch(option){ case 1: ..; break; ... case n: .. ;break; default: flag = false; break; } } while(flag);
如果我记得C ++语法,那么可以添加一个标签来break
语句,就像goto
。 所以你想要的东西很容易写出来:
while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: break outofloop; // **HERE, I want to break out of the loop itself** } } outofloop: // rest of your code here
while(true) { switch(x) { case 1: { break; } break; case 2: //some code here break; default: //some code here } }