问题
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