我正在尝试实现一个如下所示的派生特征:
#[derive(Cacheable)]
#[cacheable(directory = "path/in/cache")]
pub struct Something {
#[cacheable(id)]
pub id: String
}
其中
id
只是一个用于唯一存储数据的字段。只有其中一个字段应标有 id
,并且没有任何与之关联的数据。我们只需要字段的名称。例如该特征具有 fn id() -> String { return self.#id_field.to_string() }
我拥有它,这样我就可以使用豪华库提取
directory
,但我不知道如何获取id
标签。
fn cacheable_derive_impl(
item: proc_macro2::TokenStream,
) -> deluxe::Result<proc_macro2::TokenStream> {
// parse
let mut ast: syn::DeriveInput = syn::parse2(item)?;
// extract struct attributes
let CacheableAttributes { directory } = deluxe::extract_attributes(&mut ast)?;
// extract field attributes
// Need to get the single field marked with the id attribute
let id = if let syn::Data::Struct(s) = &mut ast.data //??
...
}
我发现的所有示例似乎都在尝试提取属性的值,或者在所有字段上都有该属性。
那么问题是,如何获取字段名称并在定义中使用它?
我使用 parse_nested_meta 找到了答案:
// extract field attributes
// Need to get the single field marked with the id attribute
let id_field = if let syn::Data::Struct(s) = &ast.data {
s.fields
.iter()
.find(|field| {
field.attrs.iter().any(|attr| {
let mut is_id = false;
if attr.path().is_ident("cacheable") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("id") {
is_id = true;
}
Ok(())
})
.unwrap();
}
is_id
})
})
.map(|field| field.ident.as_ref().unwrap().to_owned())
} else {
None
}
.ok_or_else(|| syn::Error::new_spanned(&ast, "No field with 'id' attribute found"))?;
我对它看起来有多复杂并不完全满意,但至少它有效。