How to break out of a do-while style loop in Rust?
Rust允许一种do-while循环,例如:
所以C风格:
1 2 3
| do {
something();
} while (test()); |
可以用Rust编写为:
1 2 3 4
| while {
something();
test()
}{} |
但是,在这种情况下使用break会有一个问题:
所以这个C风格:
1 2 3 4 5
| do {
if (something()) {
break;
}
} while (test()); |
不能用Rust编写为:
1 2 3 4 5 6
| while {
if (something()) {
break;
}
test()
}{} |
无法使用cannot break outside of a loop进行编译。
有没有办法打破这种形式的while循环?
注1)使用原因:do {...} while test()代替while test() {...}的是流量控制,在这种情况下,test()在最初进入循环时将是false。
注2)使用while {...}流控制时:在代码正文中调用continue将跳过最后的break检查。
请参阅相关问题:如何在宏中包装do-while样式循环,以保持连续流控制?
-
为什么不loop { * code * if test() { break; } }?
-
我不得不说,我认为这是一个可怕的骇客(针对那些以前没有看过的人的链接)。第一组括号实际上不是while循环主体-它们是条件,这就是为什么您无法爆发。 while { break } {}没有任何意义,这就是为什么此语法可能有害无益的原因。
-
@Neikos,当在宏中定义循环并以代码体作为参数传入时,使用continue会导致非显而易见的无限循环,因为中断永远不会运行。
-
@ Aurora0001一个勒芒是另一种勒芒模式。 :)我已经见过这种Lisp方言所使用的这种样式,它们缺乏本机执行时间(例如Emacs Lisp),并且一旦习惯了就可以阅读。我同意,一旦需要break和continue,使用自定义放置的中断逻辑切换到loop可能是一个更好的主意。
-
@ user4815162342,也许是这样,但是在我看来,最好还是采取防御措施,并假定程序员阅读您的代码并不像您那样聪明,并且不会注意到这种模式。如果没有指出并思考它,我绝对不会知道正在发生的事情。
-
显然,这对于编写可读代码的普通情况而言并没有什么用。最好使用诸如unsafe之类的技巧,这是没有更好选择的情况下的不得已的手段。经过研究,似乎几乎每次都有更好的选择。
-
@ Aurora0001我同意防御性-正如他们所说,"编写代码就像是下一个维护者知道您的住所的疯子一样。"另一方面,一些非常有用的习语在初次遇到时看起来像垃圾,但是经过一段时间后,他们学会了识别,使用甚至欣赏它们。 (Rust有很多类似的功能,这些功能起初看起来很奇怪,例如使用;来确定是否返回值。)Rust仍然是一门年轻的语言,尚需拭目以待。被社区视为有用的习语。
如评论中所述,了解此模式的工作原理很重要。 它不是while的特殊形式,它只是滥用循环测试来完成通常在体内完成的事情。 由于break和continue不属于循环测试(除非该循环是另一个循环的一部分,在这种情况下它们将进行编译,但会中断/继续外部循环),因此Rust拒绝了它们。
用上述模式模拟break的一种直接方法是将测试代码移到一个可以用return退出的闭包中:
1 2 3 4 5 6
| while (|| {
if something() {
return false // break
}
test()
})() {} |
可以通过相同的方式模拟continue,只需从闭包中返回true。
如果将其表示为宏,则可能可以使意图更清晰。
您想得太多了。
让我们建立一个真值表:
1 2 3 4 5 6 7 8 9 10 11
| +-------------+--------+--------+
| something() | test() | Result |
+-------------+--------+--------+
| true | true | stop |
+-------------+--------+--------+
| true | false | stop |
+-------------+--------+--------+
| false | true | go on |
+-------------+--------+--------+
| false | false | stop |
+-------------+--------+--------+ |
因此,可以这样写:
1
| while !something() && test {} |
不需要break。
-
我无法使用此逻辑的原因是test首次进入循环时为假,请在问题中作为注释添加。