我正在尝试编写一个允许我使用字段名称和结构声明类型的 Rust 宏,但我仍然需要发出该结构。
我已经使用可选属性、结构的可见性(感谢 The Little Book of Rust Macros ),但无法弄清楚如何处理 pub
在个人中的可选存在字段。
到目前为止我有:
macro_rules! with_generic {
($(#[$struct_meta:meta])*
pub struct $name:ident { $($fname:ident : $ftype:ty), *}
) => {
with_generic![(pub) $(#[$struct_meta])* struct $name {$($fname: $ftype) ,*}];
};
($(#[$struct_meta:meta])*
struct $name:ident { $($fname:ident : $ftype:ty), *}
) => {
with_generic![() $(#[$struct_meta])* struct $name {$($fname: $ftype), *}];
};
(
($($vis:tt)*)
$(#[$struct_meta:meta])*
struct $name:ident { $($fname:ident : $ftype:ty), *}
) => {
// emit the struct here
$(#[$struct_meta])*
$($vis)* struct $name {
$($fname: $ftype,)*
}
// I work with fname and ftypes here
}
}
它适用于类似
的东西with_generic! {
#[derive(PartialEq, Eq, Debug)]
pub struct Person {
first_name: String,
last_name: String
}
}
或
with_generic! {
#[derive(PartialEq, Eq, Debug)]
struct PrivatePerson {
first_name: String,
last_name: String
}
}
但不适用于
with_generic! {
#[derive(PartialEq, Eq, Debug)]
struct MixedPerson {
pub first_name: String,
last_name: String
}
}
我想获得一些关于如何使宏在最后一个案例中工作的帮助。我觉得我可能在这里遗漏了一些基本的东西,比如用于绑定(bind)可见性的类型。如果有一种方法可以在获取字段名称和类型的同时绑定(bind)整个结构树,那也很好。
我还想了解如何让它与具有生命周期参数的结构一起工作,但也许这应该是一个单独的问题。
最佳答案
你不能。至少,不是一个单一的非递归规则。这是因为 Rust 没有用于可见性的宏匹配器。
parse-macros
crate 包含一个 parse_struct!
显示完全解析 struct
定义所需工作的宏。简短版本:您需要单独解析每个字段,每个“有 pub
”和“没有 pub
”都有一个规则。
我还要注意的是,另一种情况下您的宏还没有考虑:字段上的属性,这是文档注释工作所必需的。
很快,宏 1.1 应该会稳定下来,这可能会提供一种更简单的方法(假设您可以将宏表示为派生,并且不关心旧版本的 Rust)。
关于macros - 使用宏保持结构字段可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42003501/