rust - Rust 递归宏不适用于生成结构
问题描述
我正在尝试编写一个在 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 `:`
这里有什么问题?
这是游乐场链接
解决方案
在编写声明性宏 ( 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,
in替换mk_str
它,它会像写的那样工作。如果这对您的目标不起作用,请查看The Little Book of Rust Macros。它有一些模式可以用宏做非常复杂的事情。此答案中的大部分信息来自“AST 中的宏”部分。
推荐阅读
- asp.net - 我在使用我的项目时遇到问题,在 asp.net 核心中只显示 json 格式。这些值只是空的。在这种情况下发生了什么?
- json - 将 JSON 解组为具有多个嵌入式结构和重叠字段名称的结构
- java - 按大小排列的编号表
- python - 如何调用函数中的某个参数?
- java - Java 8 流。如何将每个枚举类型的 BigDecimal 总计聚合到自定义 bean
- javascript - 循环遍历所有不起作用的 DOM 元素
- sql - Teradata SQL - 如何将小时数添加到整数?
- reactjs - 查找后将对象合并到一个数组中
- java - 如何使用 Junit 创建可共享的测试包?
- mysql - 在 MySQL 中创建 SQL 表时遇到错误