wrongusername
wrongusername

Reputation: 18918

Is there a way to put a type name into a Rust macro?

I have the following code:

trait Trait {
    const NAME: &'static str;
    const VALUE: i64;
}

struct Struct1 {}
struct Struct2 {}

impl Trait for Struct1 {
    const NAME: &'static str = "Aardvark";
    const VALUE: i64 = 0;
}

impl Trait for Struct2 {
    const NAME: &'static str = "Zebra";
    const VALUE: i64 = 100;
}

macro_rules! print_static {
    ($n:expr, $v:expr) => {
        println!("Value of {} is {}", $n, $v);
    };
}

macro_rules! print_static2 {
    ($t:expr) => {
        println!("Value of {} is {}", $t::NAME, $t::VALUE);
    };
}

fn main() {
    print_static!(Struct1::NAME, Struct1::VALUE);
    print_static!(Struct2::NAME, Struct2::VALUE);

    //print_static2!(Struct1);
    //print_static2!(Struct2);
}

It runs as:

Value of Aardvark is 0
Value of Zebra is 100

When I uncomment the print_static2 lines, I get:

error: expected one of `,`, `.`, `?`, or an operator, found `::`
  --> src/main.rs:28:41
   |
28 |         println!("Value of {} is {}", $t::NAME, $t::VALUE);
   |                                         ^^ expected one of `,`, `.`, `?`, or an operator
...
37 |     print_static2!(Struct1);
   |     ------------------------ in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected one of `,`, `.`, `?`, or an operator, found `::`
  --> src/main.rs:28:41
   |
28 |         println!("Value of {} is {}", $t::NAME, $t::VALUE);
   |                                         ^^ expected one of `,`, `.`, `?`, or an operator
...
38 |     print_static2!(Struct2);
   |     ------------------------ in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

Is there a way to specify the type name only once so that I don't end up doing something like this?

// Incorrectly associating Struct2's value with Struct1!
print_static!(Struct1::NAME, Struct2::VALUE);

Rust Playground

Upvotes: 4

Views: 1586

Answers (1)

Tavian Barnes
Tavian Barnes

Reputation: 12922

If you want to take a type as the parameter, say that:

macro_rules! print_static {
    ($t:ty) => {
        println!("Value of {} is {}", <$t>::NAME, <$t>::VALUE);
    };
}

Here's the full list of macro parameter types.

Upvotes: 7

Related Questions