我试图创建一个宏来帮助构建结构体,但宏似乎没有完全展开,而是还剩下一个迭代。
代码
struct Hello {
name: String,
age: Option<u32>,
}
macro_rules! __hello_field {
(name: $value:expr) => {
name: $value
};
(age: $value:expr) => {
age: Some($value)
};
($field:ident: $value:expr, $($tail:tt)*) => {
__hello_field!($field: $value),
__hello_field!($($tail)*)
};
() => {};
(,) => {};
}
macro_rules! hello {
($($tail:tt)*) => {
Hello {
__hello_field!($($tail)*)
}
};
}
fn main() {
let hello_item = hello!(name: String::from("hello"), age: 10);
}
字符串
预期输出
let hello_item = Hello {
name: (String::from("hello")),
age: Some(10),
};
型
这里的空白并不重要。
编译错误
error: expected one of `,`, `:`, or `}`, found `!`
--> src/main.rs:24:26
|
23 | Hello {
| ----- while parsing this struct
24 | __hello_field!($($tail)*)
| ^ expected one of `,`, `:`, or `}`
...
30 | let hello_item = hello!(name: String::from("hello"), age: 10);
| -------------------------------------------- in this macro invocation
|
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `)`
--> src/main.rs:24:37
|
23 | Hello {
| ----- while parsing this struct
24 | __hello_field!($($tail)*)
| ^ expected one of `,`, `.`, `?`, `}`, or an operator
...
30 | let hello_item = hello!(name: String::from("hello"), age: 10);
| --------------------------------------------
| | |
| | help: try adding a comma: `,`
| in this macro invocation
|
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0063]: missing field `name` in initializer of `Hello`
--> src/main.rs:23:9
|
23 | Hello {
| ^^^^^ missing `name`
...
30 | let hello_item = hello!(name: String::from("hello"), age: 10);
| -------------------------------------------- in this macro invocation
|
= note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
型
rust-analyzer认为结果的输出
请注意,还有一个__hello_field!
宏的示例。
Hello {
name:(String::from("hello")),__hello_field!(age:10)
}
型
实际输出由VS Code rust-analyzer扩展中的“Expand macro recursively at caret”特性生成。
1条答案
按热度按时间fae0ux8s1#
Root issue
根本问题是宏是从外到内计算的。这意味着宏的最后一次迭代产生了无效的代码(即,它产生了
age: Some(10)
)。宏必须总是产生完整的,有效的Rust代码(例如整个表达式)。解决方案
使用下推累加解决了这个问题。这迫使宏从内到外进行计算。
字符串
资源