0

Given a struct Foo:

struct Foo<'a> {
    info: &'a str
}

To create an array of Foos with different strings inside, I would like to have a macro, which could be used like:

assert_eq!(make_foo!("test"; 2), [Foo { info: "test 1" }, Foo { info: "test 2" }]);

What I am confused about specifically is how to iterate over the specific number of times as specified in the second argument.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vignesh
  • 315
  • 4
  • 14

1 Answers1

1

Currently, to the best of my knowledge, it's impossible to create a macro which works exactly as you wish. It's only kind of possible. I'll explain:

  • First, there is no way to count with macros, so you can't do the "repeat this n-times" on your own. This is the reason why you can't generate the strings "test 1", "test 2" and so on. It's just not possible. You can, however, create an array of structs with only "test" as string by using the standard array initializer [val; n].
  • Second, in order to use the array initializer, the type inside the array has to be Copy. But in your case that's not a big problem, since your struct can just derive it.

So let's see, what we can do (playground):

#[derive(Clone, Copy, PartialEq, Debug)]
struct Foo<'a> {
    info: &'a str
}

macro_rules! make_foo {
    ($info:expr; $num:expr) => {
        [Foo { info: $info }; $num]
    }
}

First, we need to derive a few traits for your struct:

  • Copy, see above
  • Clone is required by Copy
  • PartialEq and Debug are required by assert_eq!()

I think the macro itself is fairly easy to understand: it's just using the array initializer internally.


But how to get exactly the behavior asked in the question?

Don't use a macro and don't use fixed size arrays. A normal function and Vec<T> is probably fine. You could, of course, also write a compiler plugin, but those are unstable right now and it's probably not worth the hassle anyway.

Community
  • 1
  • 1
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305