Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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_expr but is otherwise independent. It replaces the since-removed unstable feature concat_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