如何实现Lispian cond宏?

时间:2017-12-17 13:58:39

标签: macros rust rust-macros

预期用途:

template<typename T>
result_type
foo( T arg, std::enable_if_t<std::is_floating_point<T>::value>* = 0 );

template<typename T>
std::enable_if_t<std::is_floating_point<T>::value, result_type>
foo( T arg );

应扩展为:

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

1 个答案:

答案 0 :(得分: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表达式的类型总是推断为(),因此除非所有分支都计算为()(或分歧),否则扩展宏将生成类型不匹配错误。