假设我们有一个大块:
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) }
答案 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");
}