Intended usage:
cond! {
x > 5 => 0,
x < 3 => 1,
true => -1
}
Should expand to:
if x > 5 { 0 } else if x < 3 { 1 } else if true { -1 }
Note that it doesn't produce a catch-all else { ... }
suffix.
My attempt:
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),+ }
}};
);
However, the compiler complains about the else
keyword.
error: expected expression, found keyword `else`
--> src/main.rs:32:34
|
32 | cond! { $pred => $body } else cond! { $($preds => $bodies),+ }
| ^^^^
Macros in Rust don't perform textual substitution like the C preprocessor does. Moreover, the result of a macro is already "parsed", so you can't just append something after the macro invocation that's supposed to be part of what the macro expands to.
In your case, you can't put an else
after the first cond!
invocation because the compiler has already finished parsing the if
expression; you need to put the if
and the else
together. Likewise, when you invoke cond!
again after the else
, you need to add braces around the call, because the sequence else if
does not begin a nested if
expression.
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),+ } }
};
}
Ultimately though, this macro is pretty much useless. An if
expression without an else
clause always has its type inferred to be ()
, so unless all the branches evaluate to ()
(or diverge), the expanded macro will produce type mismatch errors.