如何将枚举变体的名称转换为 RUST 中的字符串?

How to convert the name of a enum's variant to a String in RUST?

我想知道如何在不使用任何外部包装箱的情况下为任何枚举实现一种方法,该方法将 return 变体标识符作为字符串或 &'static str。类似于:

pub enum MyEnum {

    EnumVariant1
    EnumVariant2
}

impl MyEnum {

    fn to_string(&self) -> String {
        // do Rust stuff here
    }
}

正如我在评论中所述,我认为自定义派生宏可能是最简单的选择(尽管我可能遗漏了一些东西)所以这里是一个基本实现:

// lib.rs in enum_name

extern crate self as enum_name;

pub use enum_name_derive::EnumName;

pub trait EnumName {
    fn enum_name(&self) -> &'static str;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[derive(EnumName)]
    #[allow(dead_code)]
    enum MyEnum<'a, T> {
        VariantA,
        VariantB(T, i32),
        AnotherOne { x: &'a str },
    }

    #[test]
    fn test_enum_name() {
        assert_eq!("VariantA", MyEnum::VariantA::<u32>.enum_name());
        assert_eq!("VariantB", MyEnum::VariantB(1, 2).enum_name());
        assert_eq!(
            "AnotherOne",
            MyEnum::AnotherOne::<u8> { x: "test" }.enum_name()
        );
    }
}
// lib.rs in enum_name_derive

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};

#[proc_macro_derive(EnumName)]
pub fn derive_proto_read(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    let ident = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let variants = match input.data {
        Data::Enum(data) => data.variants.into_iter().map(|variant| {
            let ident = variant.ident;
            let ident_string = ident.to_string();
            let fields = match variant.fields {
                Fields::Named(_) => quote!({ .. }),
                Fields::Unnamed(_) => quote!((..)),
                Fields::Unit => quote!(),
            };

            quote! {
                Self::#ident#fields => #ident_string
            }
        }),
        _ => panic!("not an enum"),
    };

    (quote! {
        impl #impl_generics enum_name::EnumName for #ident #ty_generics #where_clause {
            fn enum_name(&self) -> &'static str {
                match self {
                    #(#variants),*
                }
            }
        }
    })
    .into()
}