How to init a struct in a macro by example?

Background

In rust, it is very easy to init a struct:

struct Foo {
    a: usize
}

let foo = Foo { a: 1 };

Problem

However, if the struct's name is given as a parameter in macros by example, it becomes strange:

mod a {
    pub struct Foo {
        pub a: usize
    }
}

macro_rules! build_foo {
    ($Foo: ty) => {
        $Foo { a: 1 }
    };
}

fn main() {
    let foo = build_foo!(a::Foo);
}

It turns out error:

expected expression, found `a::Foo`

If I change category of $Foo to be ident, it turns out error:

no rules expected the token `::`

since the struct we give is a path not ident.

If I change category of $Foo to be path, it turns out error:

macro expansion ignores token `{` and any following

I have tried ty, ident, path, expr, item, tt, ... None of them works.

Workarounds

I know there are two workarounds:

  • make $Foo to be ident, and pass Foo directly with use a::Foo:
mod a {
    pub struct Foo {
        pub a: usize
    }
}

macro_rules! build_foo {
    ($Foo: ident) => {
        $Foo { a: 1 }
    };
}

use a::Foo;

fn main() {
    let foo = build_foo!(Foo);
}
  • Write a constructor method for Foo, and pass $Foo as ty:
mod a {
    pub struct Foo {
        pub a: usize
    }

    impl Foo {
        pub fn new(a: usize) -> Self {
            Self { a }
        }
    }
}

macro_rules! build_foo {
    ($Foo: ty) => {
        <$Foo>::new(1)
    };
}

fn main() {
    let foo = build_foo!(a::Foo);
}

I think the two methods above are workarounds, but not solutions, and I wonder how to write the correct macros by example to achieve the goals.

Would a $($Foo:tt)* argument be okay for you? I also tried path but that doesn't seem to work, so I donʼt think there is any significantly better way.

mod a {
    pub struct Foo {
        pub a: usize
    }
}

macro_rules! build_foo {
    ($($Foo:tt)*) => {
        $($Foo)* { a: 1 }
    };
}

fn main() {
    let foo = build_foo!(a::Foo);
}

It works too.

But it is strange that such a common thing can't be done easily in macros by example.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.