简体   繁体   English

如何在 Vec 中获取枚举的所有变体<t>用过程宏?</t>

[英]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 在之前的评论中所写,还有很多工作要做:

  • proc macros has to reside in their own crate (if you want to publish your work on crates.io, the proc macro crate has to be published as well); proc macros 必须驻留在它们自己的 crate 中(如果你想在 crates.io 上发布你的作品,那么 proc macros crate 也必须被发布);
  • it requires syn and quote crates in the proc macro (if don't want to reinvent the wheel).它需要 proc 宏中的synquote crates(如果不想重新发明轮子)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用生锈中的宏生成复杂的枚举变体 - How to generate complex enum variants with a macro in rust 如何用宏引入 Rust 枚举变量? - How to introduce Rust enum variants with a macro? 从 rust proc-macro 内部获取目标文件夹 - Getting the target folder from inside a rust proc-macro 有没有办法在 proc-macro crate 中拥有公共特征? - Is there a way to have a public trait in a proc-macro crate? 为什么必须在 proc-macro crate 中定义 proc-macros? - Why do proc-macros have to be defined in proc-macro crate? 如何在不知道其结构的情况下创建匹配枚举变体的宏? - How to create a macro that matches enum variants without knowing its structure? proc-macro恐慌,使用structopt使用required_unless和冲突_with - proc-macro panic with structopt using required_unless and conflicts_with 在宏中匹配类似元组的枚举变体,其中枚举类型和变体是元变量:如何编写匹配模式? - Matching tuple-like enum variants in a macro, where enum type and variants are metavariables: how do I write the matching pattern? 如何仅匹配枚举的一些变体,而不是所有变体? - How do I match only some, not all variants of an enum? 如何将枚举中的元素(变体)数量作为常数值? - How to get the number of elements (variants) in an enum as a constant value?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM