Rust 如何反思所有可用的方法和生锈类型的成员?
有没有办法打印出Rust中某个类型或实例的可用成员的完整列表 例如:Rust 如何反思所有可用的方法和生锈类型的成员?,rust,introspection,Rust,Introspection,有没有办法打印出Rust中某个类型或实例的可用成员的完整列表 例如: 在Python中,我可以使用print(dir(object)) 在C中,Clang有一个Python API,可以解析C代码并对其进行反思 由于不熟悉Rust工具,我想知道是否有某种方法可以做到这一点,无论是在运行时还是编译时,或者使用编译器功能(例如宏),或者使用外部工具 这个问题是故意宽泛的,因为确切的方法并不重要。在任何语言中,查找变量的所有方法/函数都是很常见的。我不太了解锈菌,所以我不会把问题局限于具体的发现方
- 在Python中,我可以使用
print(dir(object))
- 在C中,Clang有一个Python API,可以解析C代码并对其进行反思
我不认为这是重复的,因为这个答案可能包括使用外部工具(不一定是宏)。我不认为有任何东西可以做到这一点
通过检查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!(“无法成功解析字段”),
});
}
}
};
//返回输出令牌流,以便附加自定义派生行为。
令牌流::来自(输出)
自从行为注入到你的结构中