macro_metavar_expr_concat
The tracking issue for this feature is: #124225
In stable Rust, there is no way to create new identifiers by joining identifiers to literals or other identifiers without using procedural macros such as paste.
#![feature(macro_metavar_expr_concat)] introduces a way to do this, using the concat metavariable expression.
This feature uses the syntax from
macro_metavar_exprbut is otherwise independent. It replaces the since-removed unstable featureconcat_idents.
This is an experimental feature; it and its syntax will require a RFC before stabilization.
Overview
#![feature(macro_metavar_expr_concat)] provides the concat metavariable expression for creating new identifiers:
#![allow(unused)]
#![feature(macro_metavar_expr_concat)]
fn main() {
macro_rules! create_some_structs {
($name:ident) => {
pub struct ${ concat(First, $name) };
pub struct ${ concat(Second, $name) };
pub struct ${ concat(Third, $name) };
}
}
create_some_structs!(Thing);
}
This macro invocation expands to:
#![allow(unused)]
fn main() {
pub struct FirstThing;
pub struct SecondThing;
pub struct ThirdThing;
}
Syntax
This feature builds upon the metavariable expression syntax ${ .. } as specified in RFC 3086 (macro_metavar_expr).
concat is available like ${ concat(items) }, where items is a comma separated sequence of idents and/or literals.
Examples
Create a function or method with a concatenated name
#![allow(unused)]
#![feature(macro_metavar_expr_concat)]
fn main() {
macro_rules! make_getter {
($name:ident, $field: ident, $ret:ty) => {
impl $name {
pub fn ${ concat(get_, $field) }(&self) -> &$ret {
&self.$field
}
}
}
}
pub struct Thing {
description: String,
}
make_getter!(Thing, description, String);
}
This expands to:
#![allow(unused)]
fn main() {
pub struct Thing {
description: String,
}
impl Thing {
pub fn get_description(&self) -> &String {
&self.description
}
}
}
Create names for macro generated tests
#![allow(unused)]
#![feature(macro_metavar_expr_concat)]
fn main() {
macro_rules! test_math {
($integer:ident) => {
#[test]
fn ${ concat(test_, $integer, _, addition) } () {
let a: $integer = 73;
let b: $integer = 42;
assert_eq!(a + b, 115)
}
#[test]
fn ${ concat(test_, $integer, _, subtraction) } () {
let a: $integer = 73;
let b: $integer = 42;
assert_eq!(a - b, 31)
}
}
}
test_math!(i32);
test_math!(u64);
test_math!(u128);
}
Running this returns the following output:
running 6 tests
test test_i32_subtraction ... ok
test test_i32_addition ... ok
test test_u128_addition ... ok
test test_u128_subtraction ... ok
test test_u64_addition ... ok
test test_u64_subtraction ... ok
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s