如何在宏中包装“同时执行"样式循环,以保持“连续"流控制? [英] How to wrap a do-while style loop in a macro, maintaining 'continue' flow control?

查看:79
本文介绍了如何在宏中包装“同时执行"样式循环,以保持“连续"流控制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在锈病,一个做而式循环可以写成:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆