如何在宏中包装“同时执行"样式循环,以保持“连续"流控制? [英] How to wrap a do-while style loop in a macro, maintaining 'continue' flow control?
问题描述
在锈病,一个做而式循环可以写成:
In Rust, a do-while style loop can be written:
loop {
something();
if !test() {
break;
}
}
请注意,使用的目的,做-而形式,而不是
Note that the purpose of using the do-while form instead of while test() { something() }
, is that test()
may need to run after something()
.
这个作品,但是,当所述逻辑被包裹在一个宏,它是不太明显的是用来
This works, but when the logic is wrapped in a macro, it's less obvious what happens when continue
is used. It will skip the test, potentially entering an infinite loop:
macro_rules! loop_over_items {
($item:expr, $iter:ident, $code:block) => {
{
let first = $item.first;
let mut $iter = first;
loop {
$code
$iter = $iter.next;
if (first != $iter) {
break;
}
}
}
}
}
这个作品在碱性情况下:
This works in a basic case:
loop_over_items!(item, iter_elem, {
code_to_run;
});
但是,这可能会进入无限循环,其不是很明显乍一看:
But this may enter an infinite loop which isn't very obvious at first glance:
loop_over_items!(item, iter_elem, {
if some_test() {
continue;
}
code_to_run;
});
什么是在防锈的好方法写入一个宏载体使用的
What would be a good method in Rust to write a macro that supports use of continue
skipping the logic after $code
?
推荐答案
要扩大在 ideasman42自己的答案的想法时,执行在测试它是否包含一个循环迭代的逻辑
To expand on the idea in ideasman42's own answer, the logic of executing a loop iteration while testing whether it contained break
or continue
can itself be encapsulated in a macro:
enum LoopIteration {
Normal,
Break,
Continue,
}
macro_rules! exec_iteration {
($code: block) => {{
let mut _state = LoopIteration::Normal;
loop {
if let LoopIteration::Break = _state {
// got back here after having preparing for break - it
// means a continue happened
_state = LoopIteration::Continue;
break;
}
// prepare for break
_state = LoopIteration::Break;
$code;
// neither break nor continue occurred
_state = LoopIteration::Normal;
break;
}
_state
}}
}
使用到位,一般的DO-而宏具有用于支撑
With that in place, a general do-while macro with support for break
and continue
can be written as follows:
macro_rules! do_while {
($code: block, $test: expr) => {{
loop {
match exec_iteration!($code) {
LoopIteration::Normal => (),
LoopIteration::Break => break,
LoopIteration::Continue => continue,
}
if !$test {
break;
}
}
}}
}
因为我们可以简单地嵌入在
The above is not very useful because we could have simply embedded the $code
in the loop with the same effect. But when implementing a macro like loop_over_items
, there is now a way to move to the next item after $code
even if it uses continue
:
macro_rules! loop_over_items {
($item:expr, $iter:ident, $code:block) => {{
let first = $item.first;
let mut $iter = first;
loop {
if let LoopIteration::Break = exec_iteration!($code) {
break
}
// Advance the iterator before proceeding, even if
// "continue" was used
$iter = $iter.next;
if first != $iter {
break;
}
}
}}
}
这篇关于如何在宏中包装“同时执行"样式循环,以保持“连续"流控制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!