【问题标题】:How to convert the name of a enum's variant to a String in RUST?如何将枚举变量的名称转换为 RUST 中的字符串?
【发布时间】:2021-06-18 20:46:57
【问题描述】:

我想知道如何为任何枚举实现一个方法,它将变体标识符作为字符串或 &'static str 返回,而不使用任何外部板条箱。比如:

pub enum MyEnum {

    EnumVariant1
    EnumVariant2
}

impl MyEnum {

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

【问题讨论】:

  • 如果您派生Debug,则调试格式会为单位变体执行此操作。
  • 或者如果您的变体可能类似于结构/元组并且您只想要名称,那么创建自己的简单派生宏可能是最简单的解决方案

标签: string rust enums type-conversion


【解决方案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()
}

【讨论】:

  • 你好。在 enum_name_derive 中的 lib.rs 上,我对第二个有点困惑。你能提供进一步的解释吗?感谢您的建议。
  • @Pyzyryab 这是一个普通的派生宏,你可以阅读那些here 并查看一个稍微复杂的示例here。
  • 大声笑。没想到这就像 normal way 创建您的派生宏。标记为已解决。
猜你喜欢
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
  • 2012-04-12
  • 2011-07-02
  • 2017-10-13
  • 2021-01-04
  • 2016-07-30
  • 1970-01-01
相关资源
最近更新 更多