macro_metavar_expr_concat - The Rust Unstable Book

## 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