如何使用 proc-macro 获取 Vec<T> 中枚举的所有变体?

Ale*_*ara 6 enums rust

我想知道如何为任何枚举实现一种方法,该方法将返回一种Vec<T>或某种集合类型中的所有变体。就像是:

pub enum MyEnum {
    EnumVariant1
    EnumVariant2
    ...
}

impl MyEnum {
    fn values(&self) -> Vec<MyEnum> {
        // do Rust stuff here
    }
}
Run Code Online (Sandbox Code Playgroud)

yol*_*yer 4

或者,您可以使用 proc 宏,使其通用(灵感来自How to get the number of elements (variants) in an enum as a Constant value?):

\n
extern crate proc_macro;\nextern crate syn;\n#[macro_use]\nextern crate quote;\n\nuse proc_macro::TokenStream;\n\n#[proc_macro_derive(AllVariants)]\npub fn derive_all_variants(input: TokenStream) -> TokenStream {\n    let syn_item: syn::DeriveInput = syn::parse(input).unwrap();\n\n    let variants = match syn_item.data {\n        syn::Data::Enum(enum_item) => {\n            enum_item.variants.into_iter().map(|v| v.ident)\n        }\n        _ => panic!("AllVariants only works on enums"),\n    };\n    let enum_name = syn_item.ident;\n\n    let expanded = quote! {\n        impl #enum_name {\n            pub fn all_variants() -> &\'static[#enum_name] {\n                &[ #(#enum_name::#variants),* ]\n            }\n        }\n    };\n    expanded.into()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后你可以像这样使用它:

\n
use all_variants::AllVariants;\n\n#[derive(AllVariants, Debug)]\nenum Direction {\n    Left,\n    Top,\n    Right,\n    Bottom,\n}\n\nfn main() {\n    println!("{:?}", Direction::all_variants());\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
extern crate proc_macro;\nextern crate syn;\n#[macro_use]\nextern crate quote;\n\nuse proc_macro::TokenStream;\n\n#[proc_macro_derive(AllVariants)]\npub fn derive_all_variants(input: TokenStream) -> TokenStream {\n    let syn_item: syn::DeriveInput = syn::parse(input).unwrap();\n\n    let variants = match syn_item.data {\n        syn::Data::Enum(enum_item) => {\n            enum_item.variants.into_iter().map(|v| v.ident)\n        }\n        _ => panic!("AllVariants only works on enums"),\n    };\n    let enum_name = syn_item.ident;\n\n    let expanded = quote! {\n        impl #enum_name {\n            pub fn all_variants() -> &\'static[#enum_name] {\n                &[ #(#enum_name::#variants),* ]\n            }\n        }\n    };\n    expanded.into()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但正如 @Denys S\xc3\xa9guret 在之前的评论中所写,还有很多工作要做:

\n
    \n
  • proc 宏必须驻留在自己的 crate 中(如果您想在 crates.io 上发布您的作品,则 proc 宏 crate 也必须发布);
  • \n
  • 它需要synquote在 proc 宏中打包(如果不想重新发明轮子)。
  • \n
\n