使用程序宏的解决方案 由于程序宏与声明性宏相比更为复杂,因此您最好阅读一些参考文献( ref1 , ref2 , ref3 )之前.我们将要编写一个名为"Instrospect"的 custom derive .要创建此自定义派生,我们需要将结构解析为 TokenStream syn 板条箱的帮助. #[proc_macro_derive(Introspect)]pub fn derive_introspect(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ItemStruct); // ...} 因为我们的输入可以解析为 ItemStruct 并且ItemStruct具有 fields() 方法中,我们可以使用它来获取结构的字段. 获得这些字段后,我们可以将其解析为命名字段,并可以相应地打印它们的field name和field type. input .fields .iter() .for_each(|field| match field.parse_named() { Ok(field) => println!("{:?}", field), Err(_) => println!("Field can not be parsed successfully"), }); 如果要将这种行为附加到您的自定义派生,则可以在 quote的帮助下使用以下内容板条箱: let name = &input.ident;let output = quote! { impl #name { pub fn introspect(){ input .fields .iter() .for_each(|field| match field.parse_named() { Ok(field) => println!("{:?}", field), Err(_) => println!("Field can not be parsed successfully"), }); } }};// Return output TokenStream so your custom derive behavior will be attached.TokenStream::from(output) 由于行为是作为自省功能注入到您的结构中的,因此您可以像下面这样在应用程序中调用它: #[derive(Introspect)]struct MyStruct { num: i32, text: String}MyStruct::introspect(); 注意:由于您要查找的示例类似于这个问题.此 Proc宏答案和声明性宏答案也应该为您提供见识 Is there a way to print out a complete list of available members of a type or instance in Rust?For example:In Python, I can use print(dir(object))In C, Clang has a Python API that can parse C code and introspect it.Being unfamiliar with Rust tools, I'm interested to know if there is some way to do this, either at run-time or compile-time, either with compiler features (macros for example), or using external tools.This question is intentionally broad because the exact method isn't important. It is common in any language to want to find all of a variable's methods/functions. Not knowing Rust well, I'm not limiting the question to specific methods for discovery.The reason I don't define the exact method is that I assume IDEs will need this information, so there will need to be some kinds of introspection available to support this (eventually). For all I know, Rust has something similar.I don't think this is a duplicate of Get fields of a struct type in a macro since this answer could include use of external tools (not necessarily macros). 解决方案 Currently, there is no such built-in API that you can get the fields at runtime. However you can retrieve fields by using two different ways.Declarative MacrosProcedural MacrosSolution By Using Declarative Macromacro_rules! generate_struct { ($name:ident {$($field_name:ident : $field_type:ty),+}) => { struct $name { $($field_name: $field_type),+ } impl $name { fn introspect() { $( let field_name = stringify!($field_name); let field_type = stringify!($field_type); println!("Field Name: {:?} , Field Type: {:?}",field_name,field_type); )* } } };}generate_struct! { MyStruct { num: i32, s: String } }fn main() { MyStruct::introspect();}This will give you the output:Field Name: "num" , Field Type: "i32"Field Name: "s" , Field Type: "String"PlaygroundSolution Using Procedural MacroSince procedural macros are more complicated from the declarative macros, you better to read some references(ref1, ref2, ref3) before starting.We are going to write a custom derive which is named "Instrospect". To create this custom derive, we need to parse our struct as a TokenStream with the help of syn crate.#[proc_macro_derive(Introspect)]pub fn derive_introspect(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ItemStruct); // ...}Since our input can be parsed as ItemStruct and ItemStruct has the fields() method in it, we can use this to get fields of our struct. After we get these fields, we can parse them as named and we can print their field name and field type accordingly.input .fields .iter() .for_each(|field| match field.parse_named() { Ok(field) => println!("{:?}", field), Err(_) => println!("Field can not be parsed successfully"), });If you want to attach this behavior to your custom derive you can use the following with the help of the quote crate:let name = &input.ident;let output = quote! { impl #name { pub fn introspect(){ input .fields .iter() .for_each(|field| match field.parse_named() { Ok(field) => println!("{:?}", field), Err(_) => println!("Field can not be parsed successfully"), }); } }};// Return output TokenStream so your custom derive behavior will be attached.TokenStream::from(output)Since the behaviour injected to your struct as introspect function, you can call it in your application like following:#[derive(Introspect)]struct MyStruct { num: i32, text: String}MyStruct::introspect();Note: Since the example you are looking for similar to this question. This Proc Macro Answer and Declarative Macro Answer should give you insight as well 这篇关于如何自省所有Rust类型的可用方法和成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-29 02:51