接受 proc 宏属性的多个值
Accept multiple values on proc macro attribute
我希望能够从这样的属性中检索内容:
#[foreign_key(table = "some_table", column = "some_column")]
这就是我正在尝试的方式:
impl TryFrom<&&Attribute> for EntityFieldAnnotation {
type Error = syn::Error;
fn try_from(attribute: &&Attribute) -> Result<Self, Self::Error> {
if attribute.path.is_ident("foreign_key") {
match attribute.parse_args()? {
syn::Meta::NameValue(nv) =>
println!("NAME VALUE: {:?}, {:?}, {:?}",
nv.path.get_ident(),
nv.eq_token.to_token_stream(),
nv.lit.to_token_stream(),
),
_ => println!("Not interesting")
}
} else {
println!("No foreign key")
}
// ... More Rust code
}
如果我只放一个 NameValue
就一切正常。当我添加逗号时,
一切都坏了。
唯一错误:
error: unexpected token
我怎样才能修正我的逻辑以实现不止一个的可能性NameValue
?
谢谢
更新:在写这个答案时,我忘记了 Meta
也有 List
变体,这给了你 NestedMeta
。我通常更愿意这样做,而不是我在下面的答案中所做的,以获得更大的灵活性。
虽然,对于您的特定情况,使用 Punctuated
对我来说仍然更简单、更清晰。
MetaNameValue
仅代表一对 name-value。在您的情况下,它由 ,
分隔,因此,您需要将所有这些分隔值解析为 MetaNameValue
。
您可以使用 parse_args_with along with Punctuated::parse_terminated:
而不是调用 parse_args
use syn::{punctuated::Punctuated, MetaNameValue, Token};
let name_values: Punctuated<MetaNameValue, Token![,]> = attribute.parse_args_with(Punctuated::parse_terminated).unwrap(); // handle error instead of unwrap
上面的 name_values
具有类型 Punctuated,它是一个迭代器。您可以遍历它以在您的属性中获得各种 MetaNameValue
。
根据评论更新:
从 MetaNameValue
中获取 String
的价值:
let name_values: Result<Punctuated<MetaNameValue, Token![,]>, _> = attr.parse_args_with(Punctuated::parse_terminated);
match name_values {
Ok(name_value) => {
for nv in name_value {
println!("Meta NV: {:?}", nv.path.get_ident());
let value = match nv.lit {
syn::Lit::Str(v) => v.value(),
_ => panic!("expeced a string value"), // handle this err and don't panic
};
println!( "Meta VALUE: {:?}", value )
}
},
Err(_) => todo!(),
};
我希望能够从这样的属性中检索内容:
#[foreign_key(table = "some_table", column = "some_column")]
这就是我正在尝试的方式:
impl TryFrom<&&Attribute> for EntityFieldAnnotation {
type Error = syn::Error;
fn try_from(attribute: &&Attribute) -> Result<Self, Self::Error> {
if attribute.path.is_ident("foreign_key") {
match attribute.parse_args()? {
syn::Meta::NameValue(nv) =>
println!("NAME VALUE: {:?}, {:?}, {:?}",
nv.path.get_ident(),
nv.eq_token.to_token_stream(),
nv.lit.to_token_stream(),
),
_ => println!("Not interesting")
}
} else {
println!("No foreign key")
}
// ... More Rust code
}
如果我只放一个 NameValue
就一切正常。当我添加逗号时,
一切都坏了。
唯一错误:
error: unexpected token
我怎样才能修正我的逻辑以实现不止一个的可能性NameValue
?
谢谢
更新:在写这个答案时,我忘记了 Meta
也有 List
变体,这给了你 NestedMeta
。我通常更愿意这样做,而不是我在下面的答案中所做的,以获得更大的灵活性。
虽然,对于您的特定情况,使用 Punctuated
对我来说仍然更简单、更清晰。
MetaNameValue
仅代表一对 name-value。在您的情况下,它由 ,
分隔,因此,您需要将所有这些分隔值解析为 MetaNameValue
。
您可以使用 parse_args_with along with Punctuated::parse_terminated:
而不是调用parse_args
use syn::{punctuated::Punctuated, MetaNameValue, Token};
let name_values: Punctuated<MetaNameValue, Token![,]> = attribute.parse_args_with(Punctuated::parse_terminated).unwrap(); // handle error instead of unwrap
上面的 name_values
具有类型 Punctuated,它是一个迭代器。您可以遍历它以在您的属性中获得各种 MetaNameValue
。
根据评论更新:
从 MetaNameValue
中获取 String
的价值:
let name_values: Result<Punctuated<MetaNameValue, Token![,]>, _> = attr.parse_args_with(Punctuated::parse_terminated);
match name_values {
Ok(name_value) => {
for nv in name_value {
println!("Meta NV: {:?}", nv.path.get_ident());
let value = match nv.lit {
syn::Lit::Str(v) => v.value(),
_ => panic!("expeced a string value"), // handle this err and don't panic
};
println!( "Meta VALUE: {:?}", value )
}
},
Err(_) => todo!(),
};