我想以编程方式阅读attributes。例如,我有一个具有附加到每个字段的属性的结构:
#[derive(Clone, Debug, PartialEq, Message)]
pub struct Person {
#[prost(string, tag="1")]
pub name: String,
/// Unique ID number for this person.
#[prost(int32, tag="2")]
pub id: i32,
#[prost(string, tag="3")]
pub email: String,
#[prost(message, repeated, tag="4")]
pub phones: Vec<person::PhoneNumber>,
}
(source)
我想找到与电子邮件字段关联的标签。
我希望有一些类似的代码可以在运行时获取标签:
let tag = Person::email::prost::tag;
答案 0 :(得分:2)
由于属性仅在编译时是只读的,因此您需要编写过程宏来解决此问题。
您可以在宏中查找带有以下指示符的信息。
ident
meta
的属性内容找到字段名称和元之后,可以将字符串化结果与宏中给定的输入参数进行匹配,如下所示:
macro_rules! my_macro {
(struct $name:ident {
$(#[$field_attribute:meta] $field_name:ident: $field_type:ty,)*
}) => {
struct $name {
$(#[$field_attribute] $field_name: $field_type,)*
}
impl $name {
fn get_field_attribute(field_name_prm : &str) -> &'static str {
let fields = vec![$(stringify!($field_name,$field_attribute)),*];
let mut ret_val = "Field Not Found";
fields.iter().for_each(|field_str| {
let parts : Vec<&str> = field_str.split(' ').collect();
if parts[0] == field_name_prm{
ret_val = parts[2];
}
});
ret_val
}
}
}
}
my_macro! {
struct S {
#[serde(default)]
field1: String,
#[serde(default)]
field2: String,
}
}
请注意,它假定结构中的每个字段都有一个属性。每个字段声明都以,
结尾,包括最后一个字段。但是通过对正则表达式进行一些修改,您也可以将其用于可选属性。
Playground中的工作解决方案
有关指示符的更多信息,请访问reference
您还可以快速查看程序宏here