0

I've (naively) tried this, but it doesn't print anything to the screen:

macro_rules! foo {
    ($suffix:tt, $arg:expr) => {
        concat!("foo", $suffix, "(", $arg, ")");
    };
}

fn foo_i32(x: i32) {
    println!("i32 {}", x);
}

fn foo_bool(x: bool) {
    println!("bool {}", x);
}

fn main() {
    foo!("bool", true);
    foo!("i32", 1);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Shmoopy
  • 5,334
  • 4
  • 36
  • 72
  • [Here's a more principled way of writing that using the type system to advantage.](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2962e4463278bbdc4a780aa18fb39b48) Of course you can still define a `foo!` macro if you want, but using traits is more robust than naively gluing identifiers together. – trent Mar 11 '20 at 14:43

1 Answers1

2

Yes, and no.

First of, concat! generates a string, so your code is essentially the same as if you wrote:

fn main() {
    "foobool(true)";
    "fooi32(1)";
}

which is a no-op.

To generate Rust code, the macro does not need to involve strings at all:

macro_rules! foo {
    ($suffix:tt, $arg:expr) => {
        $suffix($arg);
    };
}

which you could call as foo!(foo_bool, true);.

If however you want to construct the name foo_bool from foo and bool, you need to use concat_idents, which is currently unstable and unlikely to get stable any time soon (because it causes some hygiene issues):

#![feature(concat_idents)]

macro_rules! foo {
    ($suffix:tt, $arg:expr) => {
        concat_idents!(foo_, $suffix)($arg);
    };
}

fn foo_i32(x: i32) {
    println!("i32 {}", x);
}

fn foo_bool(x: bool) {
    println!("bool {}", x);
}

fn main() {
    foo!(bool, true);
    foo!(i32, 1);
}
Cerberus
  • 8,879
  • 1
  • 25
  • 40
mcarton
  • 27,633
  • 5
  • 85
  • 95