How to analyze all available methods and members like Rust?

Is there a way to print a complete list of available type or instance members in Rust?

For instance:

  • In Python, I can use print(dir(object))
  • In C, Clang has a Python API that can parse C code and parse it.

Being unfamiliar with Rust tools, I am interested to know if there is any way to do this, either at runtime, or at compile time, or using compiler functions (such as macros), or using external tools.

This question is intentionally broad because the exact method is not important. In any language, it is customary to want to find all the variable methods / functions. Not knowing Rust well, I do not limit the question to specific methods for detection.

The reason why I do not define the exact method is because I assume that the IDE will need this information, so it will require (in the end) several types of introspection to support it. As far as I know, Rust has something similar.

I do not think that this is a duplicate of Get fields of type struct in the macro , since this answer may include the use of external tools (not necessarily macros).

+13
source share
6 answers

  Is there a way to print a complete list of available type or instance members in Rust?

There is currently no built-in API so that you can get fields at runtime. However, you can get fields in two different ways.

  1. Declarative macros

macro_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();
}

:

Field Name: "num" , Field Type: "i32"
Field Name: "s" , Field Type: "String"


, , (ref1, ref2, ref3).

custom derive "Instrospect". TokenStream syn crate.

#[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"),
    });

, :

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 Macro Answer

+7

, rustdoc, Rust, , ( ). rustdoc :

  • ( )
  • , /// //!.

rustdoc [src].

rustdoc.

API - std.

Crates

, crates.io docs.rs. crates.io.

Cargo, :

cargo doc

( ).

+2

, -, .

, , AST.

+1

, . struct/enum, . , , , , , ​​.

+1

- :

println!("{:?}", variable); // struct, enum whatever

, #:

println!("{:#?}", variable); // struct, enum whatever
0

If you need field names inside your program, then you probably need to use macros. Either wrap your structure definition in a macro and pattern matching to create some function to get their names, or use a procedural macro to get structures for features with such functions.

See examples in syn for derived traits. In particular, see syn :: Data :: Struct, which has fields.

0
source

Source: https://habr.com/ru/post/1653272/


All Articles