Yes, you can pass an arbitrary identifier to a macro and yes, you can combine identifiers into a new identifier using concat_idents!() Macro:
#![feature(concat_idents)] macro_rules! test { ($x:ident) => ({ let z = concat_idents!(hello_, $x); z(); }) } fn hello_world() { } fn main() { test!(world); }
However, as far as I know, since concat_idents!() Is itself a macro, you cannot use this concatenated identifier wherever you could use a simple identifier, only in certain places, as in the example above, and this, in my opinion, is A HUGE drawback. Just yesterday, I tried to write a macro that could remove many patterns in my code, but in the end I could not do this because macros do not support arbitrary placement of concatenated identifiers.
By the way, if I understand your idea correctly, you really don't need identifier concatenations to get unique names. Rust macros, unlike C, are hygienic . This means that all local variable names entered inside the macro will not flow to the area where this macro is called. For example, you can assume that this code will work:
macro_rules! test { ($body:expr) => ({ let x = 10; $body }) } fn main() { let y = test!(x + 10); println!("{}", y); }
That is, we create the variable x and put the expression after the declaration. It is natural to think that x in test!(x + 10) refers to this variable declared by the macro, and everything should be fine, but in fact this code will not compile:
main3.rs:8:19: 8:20 error: unresolved name `x`. main3.rs:8 let y = test!(x + 10); ^ main3.rs:3:1: 5:2 note: in expansion of test! main3.rs:8:13: 8:27 note: expansion site error: aborting due to previous error
So, if you only need the uniqueness of the local residents, you can safely do nothing and use any names you want, they will be unique automatically. This is explained in the manual, although I find that the example there is somewhat confusing.