Photo by Martin Rancourt on Unsplash
In Rust, you can define functions that can take a varying number of parameters with a recursive macro. Though, to be specific, that will make them macros and not functions. But nevertheless, you can call them in a similar way as you would call a function.
In Rust, you can define macros multiple times and the compiler will use the first definition that matches the input:
macro_rules! print_types {
($one_and_only_param:expr) => {
$one_and_only_param.print();
};
($first_param:expr, $($rest_of_params:expr),+) => {
$first_param.print();
print_types!($($rest_of_params),+);
};
}
In this case, the first macro will match if there is only one parameter. In other cases, when there are more parameters, the second macro will match.
This macro is recursive, because it will call itself again and again, with one less parameter every time, until there's only one left, at which point the first macro will match.
So if you call it like this:
fn main() {
print_types!(123, "glxblt", 900);
}
First it will expand to this:
// Automatically generated by compiler:
123.print();
print_types!("glxblt", 900);
And then this:
// Automatically generated by compiler:
123.print();
"glxblt".print();
print_types!(900);
And finally this:
// Automatically generated by compiler:
123.print();
"glxblt".print();
900.print();
In Rust, macros don't know anything about variable types. Variable types exist on semantic level (i.e. what does the code mean). Whereas macros operate on syntactic level (i.e. what does the code look like). In order to detect the type of variable, you can use a trait:
trait Print {
fn print(&self);
}
impl Print for i32 {
fn print(&self) {
println!("param type: i32, value: {}", self);
}
}
impl Print for str {
fn print(&self) {
println!("param type: str, value: {}", self);
}
}
Now our code is done and we can run it, which will print:
param type: i32, value: 123
param type: str, value: glxblt
param type: i32, value: 900
![Kristian Kristola](https://files.kiuas.io/codeblog/abax.jpg)