简体   繁体   English

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

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

I am wondering how to implement a method for any enum that will return the variant identifier as a String or &'static str, without using any external crate.我想知道如何为任何枚举实现一个方法,该方法将变量标识符作为字符串或 &'static str 返回,而不使用任何外部板条箱。 Something like:就像是:

pub enum MyEnum {

    EnumVariant1
    EnumVariant2
}

impl MyEnum {

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

As stated in my comment I believe a custom derive macro may be the easiest option (although I could be missing something) so here is a basic implementation of one:正如我的评论中所述,我相信自定义派生宏可能是最简单的选择(尽管我可能会遗漏某些内容),因此这里是一个基本实现:

// 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()
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM