How to check types within macro

I want to create a macro that prints all its arguments accept when it finds an i32, it prints "Integer"

macro_rules! f{
    ($($arg:expr),*) => {
        $(println!("{}", $arg);)*

fn main() {
    f!("hello", "world".to_string(), 43265);

macros can't specialize on types, in fact you can't specialize on types at all until we get specialization.

You can play around with specialization in nightly

1 Like

You can use specialization like so,

Note: the straight-forward approach doesn't work yet because specialization isn't complete yet,

You may be able to do something like I did in this file starting at this line:

Note that this is only if you define the type as macro input text. So if you define the structure that type belongs in inside a macro, giving that macro just the literal string denoting that type name, you can do it.

Also you might be able to accomplish what you want here using the Any type instead and getting the typename from there. Look for the docs on that.

Contrary to the other answers, here is an implementation using 100% safe and stable code that does what you asked.

macro_rules! f {
    ($($arg:expr),*) => {{
        trait PrintInteger {
            fn as_printed(&self) -> &'static str {
        impl PrintInteger for i32 {}
        trait PrintOther {
            fn as_printed(&self) -> &Self {
        impl<T: std::fmt::Display> PrintOther for &T {}
            println!("{}", (&$arg).as_printed());

fn main() {
    f!("hello", "world".to_string(), 43265);

So those impls expand within some extra curly braces you added to that macro. Are they scoped locally to just scope block? If I call that macro more than once, are there any issues?

This is cool.

I'm curious, why Rust doesn't complain about not being able to choose the method? How is it resolved it such case?

1 Like
  • <i32 as PrintInteger>::as_printed takes a & i32 as input,

  • <&'_ i32 as PrintOther>::as_printed takes a & &i32 as input,

So, not only does the method resolution not collide (each method / function is expecting different inputs), but also there is a clear order regarding which method shadows which. In this case, since &43265: &{integer} => &i32, the one not needing an auto-ref on its receiver wins.


Because of the scoping you can call it as many times as you like, it also "seals" the trait and implementations so they can only be used inside the macro.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.