Rust proc_macro_derive:如何检查字段是否为基本类型,如布尔值?
Rust proc_macro_derive: How do I check if a field is of a primitive type, like boolean?
我正在尝试过滤掉类型为 bool
的结构的所有字段。但是 syn::Type
枚举似乎没有理由,或者我读错了定义:
pub enum Type {
Array(TypeArray),
BareFn(TypeBareFn),
Group(TypeGroup),
ImplTrait(TypeImplTrait),
Infer(TypeInfer),
Macro(TypeMacro),
Never(TypeNever),
Paren(TypeParen),
Path(TypePath),
Ptr(TypePtr),
Reference(TypeReference),
Slice(TypeSlice),
TraitObject(TypeTraitObject),
Tuple(TypeTuple),
Verbatim(TokenStream),
// some variants omitted
}
我查看了 syn::Types
来源,以检查省略了哪些变体,但这并没有给我带来任何进一步的帮助。这是我到目前为止所拥有的:
#[proc_macro_derive(Creator)]
pub fn derive_creator(_item: TokenStream) -> TokenStream {
let item = parse_macro_input!(_item as syn::DeriveInput);
let item_ident = item.ident;
let fields = if let syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
..
}) = item.data
{
named
} else {
panic!("You can derive Creator only on a struct!")
};
let bool_fields = fields.iter().filter(|field|
match field.ty {
// case when field type is bool => true
_ => false
}
);
unimplemented!()
}
我走错路了吗?或者这根本不可能?还是我遗漏了什么?
我觉得可能有更简洁的方法(无需克隆和分配字符串),但过去我做过类似的事情:
match field.ty {
Type::Path(type_path) if type_path.clone().into_token_stream().to_string() == "bool" => {
true
}
_ => false
}
您可以定义一次 bool
类型,然后比较它是否相等:
let bool_ty = Type::Path(TypePath {
qself: None,
path: Path::from(Ident::new("bool", Span::call_site())),
});
if field.ty == bool_ty {
// it's a bool
}
但我不确定跨度的差异是否会影响平等。 Span
似乎 未 实施 PartialEq
,所以我猜这没问题。*
*欢迎编辑以澄清这一点。
另一种方式:
let bool_fields = fields.iter().filter(|field| {
if let Type::Path(tp) = &field.ty {
let segments = &tp.path.segments;
// Check len to avoid "bool::SomeOtherType".
if segments.len() == 1 {
return segments[0].ident == "bool";
}
}
false
});
切记:
Worth pointing out that this checks for equality by name. A type alias, a single-field tuple or core::primitive::bool will not match, although they are all bool after type resolution. – user2722968
我正在尝试过滤掉类型为 bool
的结构的所有字段。但是 syn::Type
枚举似乎没有理由,或者我读错了定义:
pub enum Type {
Array(TypeArray),
BareFn(TypeBareFn),
Group(TypeGroup),
ImplTrait(TypeImplTrait),
Infer(TypeInfer),
Macro(TypeMacro),
Never(TypeNever),
Paren(TypeParen),
Path(TypePath),
Ptr(TypePtr),
Reference(TypeReference),
Slice(TypeSlice),
TraitObject(TypeTraitObject),
Tuple(TypeTuple),
Verbatim(TokenStream),
// some variants omitted
}
我查看了 syn::Types
来源,以检查省略了哪些变体,但这并没有给我带来任何进一步的帮助。这是我到目前为止所拥有的:
#[proc_macro_derive(Creator)]
pub fn derive_creator(_item: TokenStream) -> TokenStream {
let item = parse_macro_input!(_item as syn::DeriveInput);
let item_ident = item.ident;
let fields = if let syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
..
}) = item.data
{
named
} else {
panic!("You can derive Creator only on a struct!")
};
let bool_fields = fields.iter().filter(|field|
match field.ty {
// case when field type is bool => true
_ => false
}
);
unimplemented!()
}
我走错路了吗?或者这根本不可能?还是我遗漏了什么?
我觉得可能有更简洁的方法(无需克隆和分配字符串),但过去我做过类似的事情:
match field.ty {
Type::Path(type_path) if type_path.clone().into_token_stream().to_string() == "bool" => {
true
}
_ => false
}
您可以定义一次 bool
类型,然后比较它是否相等:
let bool_ty = Type::Path(TypePath {
qself: None,
path: Path::from(Ident::new("bool", Span::call_site())),
});
if field.ty == bool_ty {
// it's a bool
}
但我不确定跨度的差异是否会影响平等。 Span
似乎 未 实施 PartialEq
,所以我猜这没问题。*
*欢迎编辑以澄清这一点。
另一种方式:
let bool_fields = fields.iter().filter(|field| {
if let Type::Path(tp) = &field.ty {
let segments = &tp.path.segments;
// Check len to avoid "bool::SomeOtherType".
if segments.len() == 1 {
return segments[0].ident == "bool";
}
}
false
});
切记:
Worth pointing out that this checks for equality by name. A type alias, a single-field tuple or core::primitive::bool will not match, although they are all bool after type resolution. – user2722968