rust - 如何在 Rust 中以编程方式读取属性
问题描述
我想以编程方式读取属性。例如,我有一个结构,它具有附加到每个字段的属性:
#[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>,
}
(来源)
我想找到与电子邮件字段关联的标签。
我希望有一些这样的代码可以在运行时获取标签:
let tag = Person::email::prost::tag;
解决方案
由于属性在编译时只读,因此您需要编写一个过程宏来解决此类问题。
您可以在宏中找到具有以下指示符的信息。
- 字段名称与
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中工作的解决方案
有关指示符的更多信息,请参见参考
您也可以在此处快速查看程序宏
推荐阅读
- javascript - 为什么我的 css 不透明度没有通过 setTimeout() 转换回原来的 0.5 状态?
- javascript - 如何使用 MySQL 迁移脚本更新大型数据集
- node.js - 有没有一种方法可以让 nodemon 在每次点击保存时跳过 app.js 中的一段代码运行?
- kendo-ui - Jquery 的 Kendo 静态下拉列表在网格中显示为“未定义”
- css - W3C CSS Validation 变量解析错误
- python - 如何与用户一起创建应用程序
- xampp - 如何解决 404 object not found 错误?
- vue.js - Nuxt setContent 无法使用tiptap 插件
- arduino - 如何通过 HTTPS(ESP8266)进行 OTA 更新?
- python - 自动选择今天最后创建的文件并发送电子邮件