Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to generate a struct with a macro?

Tags:

rust

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),)*
        }
    )
)
like image 229
Maik Klein Avatar asked Aug 09 '14 11:08

Maik Klein


1 Answers

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.
like image 136
huon Avatar answered Oct 18 '22 20:10

huon