Macros 使用宏保持结构字段的可见性
我正在尝试编写一个Rust宏,它允许我使用结构声明的字段名和类型,但我仍然需要发出结构声明 我已经使用了可选属性和结构的可见性(多亏了),但是我不知道如何处理单个字段中可选存在的Macros 使用宏保持结构字段的可见性,macros,rust,metaprogramming,encapsulation,Macros,Rust,Metaprogramming,Encapsulation,我正在尝试编写一个Rust宏,它允许我使用结构声明的字段名和类型,但我仍然需要发出结构声明 我已经使用了可选属性和结构的可见性(多亏了),但是我不知道如何处理单个字段中可选存在的pub 到目前为止,我已经: macro_rules! with_generic { ($(#[$struct_meta:meta])* pub struct $name:ident { $($fname:ident : $ftype:ty), *} ) => { with_
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 MixedPerson {
pub first_name: String,
last_name: String
}
}
我想得到一些关于如何使宏与最后一个案例一起工作的帮助。我觉得这里可能缺少一些基本的东西,比如用于绑定可见性的类型。如果有一种方法可以在获取字段名和类型的同时绑定整个结构树,那也可以
我还想学习如何让它与具有生存期参数的结构一起工作,但这可能是一个单独的问题。你不能。至少,不能使用单一的非递归规则。这是因为Rust没有用于可见性的宏匹配器 板条箱包含一个宏,该宏显示了完全解析
struct
定义所需的工作。简短版本:您需要单独解析每个字段,其中“haspub
”和“nothaspub
”各有一条规则
我还要注意的是,还有一种情况您的宏尚未考虑:字段上的属性,这是字段上的文档注释工作所必需的 很快,宏1.1就会稳定下来,这可能会提供一种更简单的方法(假设您可以将宏表示为派生,而不关心较旧版本的Rust)。Rust 1.15是在我提出这个问题后不久推出的,它提供了@DK之类的(自定义派生)支持。他说
展望未来,我认为自定义派生w/syn和quote将是执行此类操作的标准方式,并完全回避此问题,因为您不再需要手动重新发出结构。由于Rust 1.30,您可以将可见性关键字与
vis
说明符匹配。如果没有要匹配的可见性关键字,vis
元变量将不匹配任何内容,因此您甚至不需要在$()*
中使用它。这一变化使得与\u generic
的关系变得简单得多:
macro_rules! with_generic {
($(#[$struct_meta:meta])*
$sv:vis struct $name:ident { $($fv:vis $fname:ident : $ftype:ty), *}
) => {
// emit the struct here
$(#[$struct_meta])*
$sv struct $name {
$($fv $fname: $ftype,)*
}
// do whatever else you need here
}
}
“我还要注意的是,还有一种情况你的宏还没有考虑到:字段上的属性,这是它们上的文档注释工作所必需的。”啊,谢谢,我知道我忘了什么。看着你的代码(顺便说一句…惊人的东西),我现在意识到我忘记了很多其他东西,比如where子句。不过你说得对,我基本上想要一个自定义派生:有没有什么地方可以让我读到更多关于宏1.1如何帮助实现这一点的内容?@lloydmeta,这是我所不知道的。我只是想看看源代码,比如
serde-deriver
。谢谢@Shepmaster。我也发现了这个
macro_rules! with_generic {
($(#[$struct_meta:meta])*
$sv:vis struct $name:ident { $($fv:vis $fname:ident : $ftype:ty), *}
) => {
// emit the struct here
$(#[$struct_meta])*
$sv struct $name {
$($fv $fname: $ftype,)*
}
// do whatever else you need here
}
}