Rust 如何反思所有可用的方法和生锈类型的成员?

Rust 如何反思所有可用的方法和生锈类型的成员?,rust,introspection,Rust,Introspection,有没有办法打印出Rust中某个类型或实例的可用成员的完整列表 例如: 在Python中,我可以使用print(dir(object)) 在C中,Clang有一个Python API,可以解析C代码并对其进行反思 由于不熟悉Rust工具,我想知道是否有某种方法可以做到这一点,无论是在运行时还是编译时,或者使用编译器功能(例如宏),或者使用外部工具 这个问题是故意宽泛的,因为确切的方法并不重要。在任何语言中,查找变量的所有方法/函数都是很常见的。我不太了解锈菌,所以我不会把问题局限于具体的发现方

有没有办法打印出Rust中某个类型或实例的可用成员的完整列表

例如:

  • 在Python中,我可以使用
    print(dir(object))
  • 在C中,Clang有一个Python API,可以解析C代码并对其进行反思
由于不熟悉Rust工具,我想知道是否有某种方法可以做到这一点,无论是在运行时还是编译时,或者使用编译器功能(例如宏),或者使用外部工具

这个问题是故意宽泛的,因为确切的方法并不重要。在任何语言中,查找变量的所有方法/函数都是很常见的。我不太了解锈菌,所以我不会把问题局限于具体的发现方法

我之所以不定义确切的方法,是因为我假设IDE需要这些信息,所以需要一些内省来支持这一点(最终)。据我所知,锈菌也有类似的东西


我不认为这是重复的,因为这个答案可能包括使用外部工具(不一定是宏)。

我不认为有任何东西可以做到这一点


通过检查AST,可以编写一个可以实现这一点的程序。

我使用的是这样的程序:

println!("{:?}", variable); // struct, enum whatever
如果是大字体,请使用
#
版本:

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

要扩展我的评论,您可以使用锈迹文档生成器
rustdoc
,查看您要求的几乎所有内容(在编译时)<代码>rustdoc将显示:

  • 结构(包括公共成员及其impl块)
  • 列举
  • 特征
  • 功能
  • 板条箱作者用
    //
    //写的任何文档注释
rustdoc
还会自动链接到[src]链接中每个文件的源

rustdoc
的输出示例

标准库 标准库API参考可用,并且可用于
std
命名空间中的任何内容

板条箱 您可以在上获取任何板条箱的文档。每次在crates.io上发布每个板条箱时,都会自动为其生成文档

你的项目 您可以使用Cargo为您的项目生成文档,如下所示:

cargo doc

这也会自动为您的依赖项生成文档(但不是标准库)。

我有一个使用过程宏的。它使您能够访问成员信息以及有关所使用的
struct/enum
的一些简单信息。无法提供有关方法的信息,因为过程宏无法获得此信息,据我所知,没有任何方法可以提供此类信息。

如果您需要程序中的字段名,则可能需要使用宏。在宏和模式匹配中包装结构定义以创建一些函数来获取它们的名称,或者使用过程宏为具有这些函数的特征派生结构

有关衍生特征,请参见中的示例。特别是,请参见包含字段的syn::Data::Struct

有没有办法打印出Rust中某个类型或实例的可用成员的完整列表

目前,没有这样的内置API,您可以在运行时获取字段。但是,可以使用两种不同的方法检索字段


  • 使用声明性宏解决方案

    macro\u规则!生成结构{
    ($name:ident{$($field\u name:ident:$field\u type:ty),+})=>{
    结构$name{$($field\u name:$field\u type),+}
    impl$name{
    fn内省(){
    $(
    让field\u name=stringify!($field\u name);
    让field\u type=stringify!($field\u type);
    println!(“字段名:{:?},字段类型:{:?}”,字段名,字段类型);
    )*
    }
    }
    };
    }
    生成结构!{MyStruct{num:i32,s:String}
    fn main(){
    MyStruct::introspect();
    }
    
    这将为您提供以下输出:

    字段名:“num”,字段类型:“i32”
    字段名称:“s”,字段类型:“字符串”
    


    使用程序宏的解决方案

    由于过程宏比声明性宏更复杂,因此在开始之前最好阅读一些引用(,)

    我们将要编写一个名为
    “Instrospect”
    。要创建这个自定义派生,我们需要在crate的帮助下将结构解析为

    #[proc_macro_派生(内省)]
    发布fn派生_内省(输入:TokenStream)->TokenStream{
    让输入=parse_macro_input!(输入为ItemStruct);
    // ...
    }
    
    由于我们的输入可以解析为,并且
    ItemStruct
    中有方法,因此我们可以使用它来获取结构的字段

    得到这些字段后,我们可以将它们解析为命名字段,并相应地打印它们的
    字段名
    字段类型

    输入
    .菲尔德
    .国际热核实验堆(iter)
    .for|u each(| field | match field.parse_named()){
    Ok(字段)=>println!(“{:?}”,字段),
    Err()=>println!(“无法成功解析字段”),
    });
    
    如果要将此行为附加到自定义衍生,可以在板条箱的帮助下使用以下选项:

    let name=&input.ident;
    让输出=报价!{
    impl#name{
    pub fn内省(){
    输入
    .菲尔德
    .国际热核实验堆(iter)
    .for|u each(| field | match field.parse_named()){
    Ok(字段)=>println!(“{:?}”,字段),
    Err()=>println!(“无法成功解析字段”),
    });
    }
    }
    };
    //返回输出令牌流,以便附加自定义派生行为。
    令牌流::来自(输出)
    
    自从行为注入到你的结构中