Rust recursive macro not working for generating struct

余生颓废 提交于 2021-01-03 08:47:05

问题


I am trying to write a macro that generates a struct in Rust. This macro will add different Serde attributes to struct fields based on the type of field. This is the final goal.

For now, I'm simply trying to write a macro that uses another macro for generating a recursive code.

This is what the code looks like:

macro_rules! f_list {
    ($fname: ident, $ftype: ty) => {
        pub $fname: $ftype,
    }
}

macro_rules! mk_str {
    ($sname: ident; $($fname: ident: $ftype: ty,)+) => {
        #[derive(Debug, Clone)]
        pub struct $sname {
            $(
                f_list!($fname, $ftype)
            )+
        }
    }
}

mk_str! {
    Yo;
    name: String,
}

fn main() {
    println!("{:?}", Yo { name: "yo".to_string() })
}

This code on running gives below error, which I'm not able to understand.

error: expected `:`, found `!`
  --> src/main.rs:12:23
   |
12 |                   f_list!($fname, $ftype);
   |                         ^ expected `:`

What's wrong here?

Here's a playground link


回答1:


When writing declarative macros (macro_rules!), it's important to understand that the output of a macro must be a pattern, a statement, an expression, an item or an impl. Effectively, you should think of the output as something that can stand alone, syntactically speaking.

In your code, the macro f_list, if it worked, would output code like

name1: type1,
name2: type2,
name3: type3,

While this could be part of a declaration for a struct, it is not itself something that can stand alone.

Why is the error in the other macro then? mk_str successfully expands to

#[derive(Debug, Clone)]
pub struct Yo {
    f_list!(name, String)
}

However, the parser doesn't expect a macro inside of a struct declaration. The inside of a struct isn't a pattern, a statement, an expression, an item or an impl. Thus, when it sees the !, it gives up and reports an error.

How can you fix this? In this particular example, f_list is fairly redundant. You could simply replace f_list!($fname, $ftype) with pub $fname: $ftype, in mk_str and it'll work as written. If this doesn't work for your goal, take a look at The Little Book of Rust Macros. It has some patterns for doing very complicated things with macros. Most of the information in this answer came from the section "Macros in the AST".



来源:https://stackoverflow.com/questions/55016180/rust-recursive-macro-not-working-for-generating-struct

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!