如何实现Lispian cond宏?

问题描述 投票:0回答:1

预期用途:

cond! {
  x > 5 => 0,
  x < 3 => 1,
  true => -1
}

应扩展到:

if x > 5 { 0 } else if x < 3 { 1 } else if true { -1 }

请注意,它不会产生一个全能的else { ... }后缀。

我的尝试:

macro_rules! cond(
    ($pred:expr => $body:expr) => {{
        if $pred {$body}
    }};
    ($pred:expr => $body:expr, $($preds:expr => $bodies:expr),+) => {{
        cond! { $pred => $body } else cond! { $($preds => $bodies),+ }
    }};
);

但是,编译器抱怨else关键字。

error: expected expression, found keyword `else`
  --> src/main.rs:32:34
   |
32 |           cond! { $pred => $body } else cond! { $($preds => $bodies),+ }
   |                                    ^^^^
macros rust rust-macros
1个回答
3
投票

Rust中的宏不像C预处理器那样执行文本替换。而且,宏的结果已经被“解析”了,所以你不能只是在宏调用之后附加一些东西,它应该是宏扩展到的一部分。

在你的情况下,你不能在第一次else调用之后放一个cond!,因为编译器已经完成了解析if表达式;你需要把ifelse放在一起。同样,当您在cond!之后再次调用else时,您需要在调用周围添加大括号,因为序列else if不会开始嵌套的if表达式。

macro_rules! cond {
    ($pred:expr => $body:expr) => {
        if $pred { $body }
    };
    ($pred:expr => $body:expr, $($preds:expr => $bodies:expr),+) => {
        if $pred { $body } else { cond! { $($preds => $bodies),+ } }
    };
}

但最终,这个宏几乎没用。没有if子句的else表达式总是将其类型推断为(),因此除非所有分支都评估为()(或发散),否则扩展的宏将产生类型不匹配错误。

© www.soinside.com 2019 - 2024. All rights reserved.