[英]How to get all the variants of an enum in a Vec<T> with a proc-macro?
I am wondering how to implement a method for any enum that will return all variants in a Vec<T>
or some kind of collection type.我想知道如何为任何枚举实现一个方法,该方法将返回Vec<T>
或某种集合类型中的所有变体。 Something like:就像是:
pub enum MyEnum {
EnumVariant1
EnumVariant2
...
}
impl MyEnum {
fn values(&self) -> Vec<MyEnum> {
// do Rust stuff here
}
}
There's no smart and standard solution.没有智能和标准的解决方案。
An obvious one is to declare the array yourself, by repeating the variants:一个明显的方法是通过重复变量来自己声明数组:
static VARIANTS: &[MyEnum] = &[
MyEnum::EnumVariant1,
MyEnum::EnumVariant2,
];
This is a reasonable solution.这是一个合理的解决方案。 When your code evolve, it's frequent you discover you don't want all variants in your static array.当您的代码不断发展时,您经常会发现您并不需要 static 数组中的所有变体。 Or that you need several arrays.或者你需要几个 arrays。
Alternatively, if there are many elements or several enums, you may create a macro for this purpose:或者,如果有很多元素或多个枚举,您可以为此创建一个宏:
macro_rules! make_enum {
(
$name:ident $array:ident {
$( $variant:ident, )*
}
) => {
pub enum $name {
$( $variant, )*
}
static $array: &[$name] = &[
$( $name::$variant, )*
];
}
}
make_enum! (MyEnum VARIANTS {
EnumVariant1,
EnumVariant2,
});
This make_enum!
这个make_enum!
macro call would create both the enum and a static array called VARIANTS
.宏调用将创建枚举和一个名为VARIANTS
的 static 数组。
Alternatively you can use a proc macro which makes it generic (inspired by How to get the number of elements (variants) in an enum as a constant value? ):或者,您可以使用使其通用的 proc 宏(受How to get the number of elements (variants) in an enum as a constant value?启发):
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(AllVariants)]
pub fn derive_all_variants(input: TokenStream) -> TokenStream {
let syn_item: syn::DeriveInput = syn::parse(input).unwrap();
let variants = match syn_item.data {
syn::Data::Enum(enum_item) => {
enum_item.variants.into_iter().map(|v| v.ident)
}
_ => panic!("AllVariants only works on enums"),
};
let enum_name = syn_item.ident;
let expanded = quote! {
impl #enum_name {
pub fn all_variants() -> &'static[#enum_name] {
&[ #(#enum_name::#variants),* ]
}
}
};
expanded.into()
}
Then you can use it like this:然后你可以像这样使用它:
use all_variants::AllVariants;
#[derive(AllVariants, Debug)]
enum Direction {
Left,
Top,
Right,
Bottom,
}
fn main() {
println!("{:?}", Direction::all_variants());
}
Output: Output:
[Left, Top, Right, Bottom]
But as @Denys Séguret wrote in a previous comment, it's lot more work:但正如@Denys Séguret 在之前的评论中所写,还有很多工作要做:
syn
and quote
crates in the proc macro (if don't want to reinvent the wheel).它需要 proc 宏中的syn
和quote
crates(如果不想重新发明轮子)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.