10
trait Print {
    fn print(&self);
}
struct Printer {
    p: Box<Print>,
}
fn main() {
    let i = 1i32;
    let s = String::from_str("Hello");

    // let mp = make_printer!(i,s);
    let mp = |i: i32, s: String| {
        struct Foo {
            i: i32,
            s: String,
        }
        impl Foo {
            fn new(i: i32, s: String) -> Foo {
                Foo { i: i, s: s }
            }
        }
        impl Print for Foo {
            fn print(&self) {
                println!("{} {}", self.i, self.s);
            }
        }
        Printer { p: box Foo::new(i, s) }
    };

    let printer = mp(i, s);
    printer.p.print();
}

I want to create the make_printer! macro which should expand to mp if I call it with make_printer!(i,s).

Is this is possible? I think the biggest issue here is that I need something like decltype from C++ so that I can extract the type from a variable. The struct could then look like:

#![feature(macro_rules)]
macro_rules! make_printer(
    ($($element:ident),*) => (
        struct Foo{
            $($element : decltype($element),)*
        }
    )
)
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Maik Klein
  • 15,548
  • 27
  • 101
  • 197
  • So we have some state, plus a method to operate on that state. And it needs to work on any type and number of types, and should be easy to build on the fly by the looks of it. That sounds like a job for closures. – A.B. Aug 09 '14 at 13:32
  • @A.B. I am not sure if we can build closures on the fly at the moment. – Maik Klein Aug 09 '14 at 14:33

1 Answers1

21

No, it's not possible to do it with just the expression identifiers. You need explicit types, e.g.

macro_rules! make_printer {
    ($($element: ident: $ty: ty),*) => {
        struct Foo { $($element: $ty),* }
    }
}

called like make_printer!(x: i32, y: String).

This is required for two, mostly orthogonal, reasons:

  • macros don't have access to any type information, they are just local syntactic transformations (e.g. it's not even possible to write a macro (either macro_rules! or procedural) that can tell if a given ident refers to a local variable).
  • Rust doesn't have a decltype equivalent.
ideasman42
  • 42,413
  • 44
  • 197
  • 320
huon
  • 94,605
  • 21
  • 231
  • 225