rust 在派生宏中使用枚举字段

w7t8yxp5  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(274)

尝试创建我自己的Serialize trait并派生宏时,当我需要访问枚举的字段时,我被卡住了。
例如,在枚举变体上:

enum MyEnum {
    MyVariant(f32, u16, u16)
}

我想做的是:

fn Serialize(self) -> Vec<u8> {
    match self {
        MyEnum::MyVariant(field0, field1, field2) => {
            let mut result = Vec::<u8>::new();
            result.append(&mut field0.Serialize());
            result.append(&mut field1.Serialize());
            result.append(&mut field1.Serialize());
            result
        }
    }
}

我的想法是在基本数据类型上实现Serialize特征,然后可以将其扩展到各种结构和枚举。
但我不知道如何在派生宏中为字段(field0、field1、field2)创建变量名,然后使用它们。
这就是我目前的工作:

// create the fields argument tokens (this is "field0, field1, field2")
let mut fields_name = TokenStream2::new();
// operation of fields (this is result.append(field0.Serialize(); [...])
let mut fields_serialization = TokenStream2::new();
// counter to create numbered names for fields
let mut counter = 0;
for _field in &fields.unnamed { // fields is of type &FieldsUnnamed here
    if counter == 0 {
        fields_name.extend(quote!{
            format!("field{}", #counter)
        })
    }
    else {
        fields_name.extend(quote!{
            , format!("field{}", #counter)
        })
    }

    fields_serialization.extend(quote_spanned! {variant.span()=>
        result.append(&mut format!("field{}", #counter).Serialize());
    });

    counter += 1;
}

quote_spanned! {variant.span()=>
    #name::#variant_name (#fields_name) => {
        let mut result = Vec::new();
        #fields_serialization
        result
    },
}

我知道使用格式宏,我最终会得到一个字符串标记,但它不起作用。但我不知道如何获得所有枚举变量字段并对其进行操作,因为我在网上找到的有关它的信息非常少。

ctehm74n

ctehm74n1#

我建议使用.enumerate()并利用quote的重复特性:

let mut field_name: Vec<_> = fields.unnamed.iter().enumerate().map(|(i, _)| {
    format_ident!("field{}", i)
}).collect();

quote_spanned! {variant.span()=>
    #name::#variant_name (#(#field_name,)*) => {
        let mut result = Vec::new();

        #(
            result.append(&mut #field_name.Serialize());
        )*

        result
    },
}

顺便说一句,在Rust中,标准的样式只适用于要大写的类型。所有的方法都应该是lower_snake_case

相关问题