是否有可能通过使用宏来删除Rust中的语句及其正文?

时间:2016-08-26 15:28:43

标签: macros rust

假设我们有一个大块:

mod module {
    pub const fiz: u32 = (1 << 0);
    // etc...
}

flag = {
    if      (var & module::fiz) != 0 { module::fiz }
    else if (var & module::foo) != 0 { module::foo }
    else if (var & module::bar) != 0 { module::bar }
    else if (var & module::baz) != 0 { module::baz }
    // .. there could be many more similar checks
};

只需更换宏即可:

#define TEST(f) ((var) & (f)) != 0 { f }

允许:

flag = {
    if      TEST(module::fiz)
    else if TEST(module::foo)
    else if TEST(module::bar)
    else if TEST(module::baz)
}

似乎Rust不允许宏声明if语句的一部分。

我设法避免重复使用任务,但它非常难看。

flag = {
    let f;
    if      (var & {f = module::fiz; f }) != 0 { f }
    else if (var & {f = module::foo; f }) != 0 { f }
    else if (var & {f = module::bar; f }) != 0 { f }
    else if (var & {f = module::baz; f }) != 0 { f }
}; 

在这种情况下,Rust是否提供了一些方便/优雅的方式来重复?

我认为标记检查不是这个问题的重要部分,问题是您可能希望在if语句的主体中再次重复检查内容,例如:

if      (foo && OTHER_EXPRESSION) { do(); something_with(OTHER_EXPRESSION) }
else if (foo && SOME_EXPRESSION)  { do(); something_with(SOME_EXPRESSION)  }

2 个答案:

答案 0 :(得分:4)

我认为你有一个X / Y问题,所以我将使用if / else来解决这个而不是

您似乎正在做的是检查是否存在位模式,并优先考虑检查所述模式的顺序(不清楚是否重要,但让我们假设它确实如此)。

所以,让我们以功能的方式做到这一点:

let constants = [fiz, foo, bar, baz];

let flag = constants.iter().filter(|v| var & *v == **v).next();

just works,没有宏观或重复的东西。

答案 1 :(得分:1)

如果要使用宏,可以这样写:

mod module {
    pub const fiz: u32 = (1 << 0);
    pub const foo: u32 = (1 << 1);
    pub const bar: u32 = (1 << 2);
    pub const baz: u32 = (1 << 3);
}

macro_rules! check_bits {
    ([$($Constant:expr),*]) => {
        |var: u32| {
            $(if ($Constant & var) != 0 {
                return $Constant;
            })*
                return 0;
        }
    }
}

fn main() {
    let var = 5;
    let checker = check_bits!([module::bar, module::fiz, module::foo, module::baz]);
    assert_eq!(checker(var), module::bar);
    println!("All OK");
}