前段时间我遇到了以下很少见过的构造,虽然我比较频繁地使用它。我通常在检查整个条件列表时使用它,并且它可以防止大量缩进。基本上它使用for循环来提供一种结构化的goto。我的问题首先是否有更好的方法来构建它,其次是人们是否喜欢它,第三是java / c ++中的新关键字(例如unit {})是否只会导致中断退出到单元的末尾有用而且更清晰。
ps我意识到它正在脱离无限循环,但我认为我对此的偏执意味着它从未发生过。
编辑:我已经为其他条件添加了一些设置代码,以尝试用链接来解决问题
boolean valid = false;
// this loop never loops
for (;;)
{
if (!condition1)
break;
condition2.setup();
if (!condition2)
break;
condition3.setup();
if (!condition3)
break;
valid = true;
break;
}
if (valid) dosomething();
编辑:
我刚刚发现,实际上有一种方法可以在java中构造它而不会滥用循环等,并且想知道这是否会同样不受欢迎,尽管我想我已经错过了这个。
重组后的代码看起来像这样。
boolean valid = false;
breakout:
{
if (!condition1)
break breakout;
condition2.setup();
if (!condition2)
break breakout;
condition3.setup();
if (!condition3)
break breakout;
valid = true;
}
if (valid) dosomething();
现在,这消除了导致很多抱怨的for循环的误用,实际上我认为这是一个非常简洁的解决方案,而且是我原本想要找到的。 我猜这个结构可能并不为人所知,因为没人提到它,人们强烈反对这个结构?
答案 0 :(得分:16)
这个循环是违反直觉的,在代码审查中会受到质疑:“如果你总是在第一次迭代中破解,为什么还需要循环?”
为什么不使用它?
boolean valid = true;
if (!condition1)
valid = false;
else if (!condition2)
valid = false;
else if (!condition3)
valid = false;
if (valid) dosomething();
答案 1 :(得分:7)
您可能听说过现代编程语言所具有的这些东西,称为 functions ;)
不再使用goto
的一个主要原因是我们现在可以将代码分解为单独的函数,而是调用它们。
解决问题的一种方法是将代码放在一个单独的函数中,而返回而不是从伪循环中断开:
void safedosomething() {
if (!condition1)
return;
condition2.setup();
if (!condition2)
return;
condition3.setup();
if (!condition3)
return;
dosomething();
}
或编写辅助函数(如bool checkcondition1() { condition1.setup(); return condition1; }
),设置然后测试条件,并使用布尔标志:
bool valid = true;
if (!checkcondition1())
valid = false;
if (!checkcondition2())
valid = false;
if (!checkcondition3())
valid = false;
if (!checkcondition4())
valid = false;
if (valid) dosomething();
或更简洁一点:
bool valid = true;
valid &&= checkcondition1();
valid &&= checkcondition2();
valid &&= checkcondition3();
valid &&= checkcondition4();
if (valid) dosomething();
或只是
if (checkcondition1()
&& checkcondition2()
&& checkcondition3()
&& checkcondition4())
dosomething();
有很多方法可以表达这一点,没有违反直觉的循环 - 不要循环。
答案 2 :(得分:4)
这种结构的原因是因为goto
是编程中的脏词。但是让我们面对它,你正在有效地使用循环结构来做同样的事情。我对此的看法要么是诚实的,要么使用goto
或重构代码。
答案 3 :(得分:3)
我不认为这是最可读的方式。链式if
- else if
看起来好多了。但是如果你想坚持下去并且不想接近无限循环,你可以这样做:
do
{
if (...)
break;
...
} while (false);
答案 4 :(得分:3)
仅限C ++:
if ( condition1
&& (condition2.setup(), condition2)
&& (condition3.setup(), condition3) )
{
dosomething();
}
对于java兼容的东西(但我还在编写C ++!),我会回过头来讨论这个问题。 (显然,某些上下文可能需要传递到CheckConditions()
。)
bool CheckConditions()
{
if (!condition1)
return false;
condition2.setup();
if (!condition2)
return false;
condition3.setup();
if (!condition3)
return false;
return true;
}
//...
if (CheckConditions())
{
dosomething();
}
//...
答案 5 :(得分:2)
您似乎担心评估条件2需要一些设置,而您不知道将它放在何处。将其重构为一个单独的布尔方法,然后使用几乎所有人在这里描述的方式。例如:
if (checkCondition1() && checkCondition2(someInput) && checkCondition3()) {
doSomething();
}
和..
private boolean checkCondition2(Object someInput) {
//setup condition 2
return condition2;
}
答案 6 :(得分:1)
我认为
的问题if (condition1 && condition2 && ...)
只是在有很多条件的情况下很难读取和编辑,尽管你总是这样写:
if ( condition1 &&
condition2 &&
condition3 ... )
doStuff();
如何将循环转换为函数:
bool all()
{
if (!condition1) return false;
if (!condition2) return false;
if (!condition3) return false;
....
return true;
}
答案 7 :(得分:1)
如果你想保持缩进的话,这就是妥协:
boolean valid = true; // optimistic start
if (!valid || !condition1)
valid = false;
if (!valid || !condition2)
valid = false;
if (!valid || !condition3)
valid = false;
if (valid)
doSomething();
第一个!valid
语句中的if
是超级流畅的,但不会造成伤害,可以保留以便于阅读。 else/if
对我来说更优雅,但这只是一种观点。
但我真的不会(ab-)使用for循环,我从来没有找到一种廉价的方法来实现伪goto。总有一个更好的解决方案。
答案 8 :(得分:0)
如果在循环结束时有break语句,我不确定为什么需要循环。不管情况如何,你只是迭代一次吗?
无论如何,你通常会在SO上找到两个不同的意见,一个是断言不应该被使用,一个是它取决于情况。
我倾向于使用后一组,但循环的工作方式使用多余的break语句。我宁愿构建这样的循环:
bool valid = true;
for(... ; .... && valid == true ; ....)
{
if (!condition1)
valid = false;
if (!condition2)
valid = false;
if (!condition3)
valid = false;
}
这允许我认为更优雅的循环退出。
答案 9 :(得分:0)
拥有如此长的if语句很可能是错误的编码。
它使测试变得非常困难,并且很可能是代码味道。
如果可能的话,你应该重构以利用多态性。
答案 10 :(得分:0)
如何将设置重定位到Condition类的operator bool?这使得它更具可读性并隐藏了机制。
class Condition
{
bool _isSet;
public:
Condition() : _isSet(false) {
}
void setup() {
_isSet = true;
}
operator bool () {
if (!_isSet) {
setup();
}
return rand() & 1;
}
};
void doSomething()
{
}
int _tmain(int argc, _TCHAR* argv[])
{
Condition cond1, cond2, cond3;
if (cond1 && cond2 && cond3) {
doSomething();
}
return 0;
}
答案 11 :(得分:0)
您可以将该代码输出到单独的函数并使用多个return语句。无论如何,您可能需要将长if
语句列表重构为单独的函数。
bool isValid()
{
if (!condition1)
return false;
condition2.setup();
if (!condition2)
return false;
condition3.setup();
if (!condition3)
return false;
return true;
}
然后你可以在你的代码中使用它:
if (isValid()) dosomething();