Rust递归宏不能用于生成struct

问题描述 投票:3回答:1

我正在尝试编写一个在Rust中生成结构的宏。此宏将根据字段类型向结构字段添加不同的Serde属性。这是最终目标。

现在,我只是想编写一个使用另一个宏来生成递归代码的宏。

这就是代码的样子:

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() })
}

这个运行代码给出了以下错误,我无法理解。

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

这有什么不对?

这是一个游乐场link

rust macros rules
1个回答
1
投票

在编写声明性宏(macro_rules!)时,重要的是要理解宏的输出必须是模式,语句,表达式,项目或impl。实际上,您应该将输出视为可以独立的,从语法上讲。

在你的代码中,宏f_list,如果它工作,将输出代码

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

虽然这可能是结构声明的一部分,但它本身并不是独立的东西。

为什么其他宏中的错误呢? mk_str成功扩展到

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

但是,解析器不期望结构声明中的宏。结构的内部不是模式,语句,表达式,项目或impl。因此,当它看到!时,它会放弃并报告错误。

你怎么解决这个问题?在这个特定的例子中,f_list相当多余。您可以简单地用f_list!($fname, $ftype)中的pub $fname: $ftype,替换mk_str,它将按照书面形式工作。如果这对您的目标不起作用,请查看The Little Book of Rust Macros。它有一些用宏来做非常复杂的事情的模式。这个答案中的大部分信息来自"Macros in the AST"部分。

© www.soinside.com 2019 - 2024. All rights reserved.