ide*_*n42 13 introspection rust
有没有办法在Rust中打印出类型或实例的可用成员的完整列表?
如果问这个问题是Python,那么答案就是print(dir(object))
.
如果问题是C,那么Clang有一个Python API可以解析C代码并对其进行内省.
不熟悉Rust工具,我很想知道是否有某种方法可以在运行时或编译时,使用编译器功能(例如宏)或使用外部工具来执行类似的操作.
请注意,这个问题是故意的,因为使用的确切方法不一定非常重要.给定一个变量,是否有办法找到它的所有方法和功能并不是一个不寻常的目标,但不能很好地了解这个领域,我不是将问题局限于特定方法.
Is there a way to print out a complete list of available members of a type or instance in Rust?
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.
Solution By Using Declarative Macro
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();
}
Run Code Online (Sandbox Code Playgroud)
This will give you the output:
Field Name: "num" , Field Type: "i32"
Field Name: "s" , Field Type: "String"
Run Code Online (Sandbox Code Playgroud)
Solution Using Procedural Macro
Since 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);
// ...
}
Run Code Online (Sandbox Code Playgroud)
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"),
});
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
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
为了扩展我的评论,您可以使用rustdoc
Rust 文档生成器来查看您要求的几乎所有内容(在编译时)。rustdoc
将会呈现:
///
或编写的任何文档注释//!
。rustdoc
还自动链接到 [src] 链接中每个文件的源。
这是输出的示例rustdoc
。
标准库 API 参考在此处可用,可用于std
命名空间中的任何内容。
您可以在docs.rs上的crates.io上获取任何可用的 crate 的文档。每次在 crates.io 上发布时,它都会自动为每个 crate 生成文档。
您可以使用 Cargo 为您的项目生成文档,如下所示:
cargo doc
Run Code Online (Sandbox Code Playgroud)
这还将自动为您的依赖项(但不是标准库)生成文档。
归档时间: |
|
查看次数: |
2212 次 |
最近记录: |