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

4

我想知道如何实现一个方法,使任何枚举在不使用任何外部 crate 的情况下返回变体标识符作为字符串或&'static str。类似这样:

pub enum MyEnum {

    EnumVariant1
    EnumVariant2
}

impl MyEnum {

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


2
如果您派生Debug,则调试格式将为单元变量执行此操作。 - Aiden4
如果您的变量可能类似于结构体/元组,并且您只想要名称,那么创建自己的简单派生宏可能是最简单的解决方案。 - F0X
1个回答

1
如我在评论中所述,我认为自定义派生宏可能是最简单的选择(虽然我可能会漏掉某些东西),因此这里是一个基本实现:
// 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()
}

嗨, 我对 lib.rs 中的 enum_name_derive 的第二个有些困惑。 你能提供更详细的解释吗?先行致谢。 - Alex Vergara
@Pyzyryab 这是一个普通的派生宏,你可以在这里了解更多信息(https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros),并查看稍微复杂一些的示例(https://github.com/dtolnay/syn/tree/master/examples/heapsize)。 - F0X

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接