我想知道如何实现一个方法,使任何枚举在不使用任何外部 crate 的情况下返回变体标识符作为字符串或&'static str。类似这样:
pub enum MyEnum {
EnumVariant1
EnumVariant2
}
impl MyEnum {
fn to_string(&self) -> String {
// do Rust stuff here
}
}
我想知道如何实现一个方法,使任何枚举在不使用任何外部 crate 的情况下返回变体标识符作为字符串或&'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()
}
Debug
,则调试格式将为单元变量执行此操作。 - Aiden4