I'm trying to create a macro in Rust that lets me write
make_list!(1, 2, 3)
instead of
Node::new(1, Node::new(2, Node::new(3, None)))
which should work for an arbitrary number of "parameters" including zero. This is what I have so far:
macro_rules! make_list(
() => (
None
);
( $x:expr, $( $more:expr ),* ) => (
Node::new($x, make_list!( $( $more ),* ))
)
);
but I get the following error:
error: unexpected end of macro invocation
--> src/main.rs:19:42
|
19 | Node::new($x, make_list!( $( $more ),* ))
| ^^^^^
I can't make much sense of this. From what I can tell, it should work. What did I do wrong?
The complete code:
type List<T> = Option<Box<Node<T>>>;
struct Node<T> {
value: T,
tail: List<T>,
}
impl<T> Node<T> {
fn new(val: T, tai: List<T>) -> List<T> {
Some(Box::new(Node::<T> {
value: val,
tail: tai,
}))
}
}
macro_rules! make_list(
() => (
None
);
( $x:expr, $( $more:expr ),* ) => (
Node::new($x, make_list!( $( $more ),* ))
)
);
fn main() {
let _list: List<i32> = make_list!(1, 2, 3, 4, 5, 6, 7, 8, 9);
}
To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments. __VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them.
Variadic functions are functions (e.g. std::printf) which take a variable number of arguments. To declare a variadic function, an ellipsis appears after the list of parameters, e.g. int printf(const char* format...);, which may be preceded by an optional comma.
The C standard mandates that the only place the identifier __VA_ARGS__ can appear is in the replacement list of a variadic macro. It may not be used as a macro name, macro argument name, or within a different type of macro. It may also be forbidden in open text; the standard is ambiguous.
The term macro refers to a family of features in Rust: declarative macros with macro_rules! and three kinds of procedural macros: Custom #[derive] macros that specify code added with the derive attribute used on structs and enums. Attribute-like macros that define custom attributes usable on any item.
Expanding on the error: you get down to the case where there is only one value, and so it writes make_list!(1)
. However, there is no rule that will match that, for the second rule, after consuming the expression x
, wants a comma, which is not provided.
So you need to make it so that it will work for make_list!(1)
and not just (in fact, just not) make_list!(1,)
. To achieve this, get the comma inside the repeating part, like this:
macro_rules! make_list(
() => (
None
);
( $x:expr $( , $more:expr )* ) => (
Node::new($x, make_list!( $( $more ),* ))
)
);
Bonus: you can write make_list![1, 2, 3]
instead of make_list!(1, 2, 3)
if you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With