在Rust中创建一个宏以获取一个Struct并按顺序将其字段类型转换为元组

omjgkv6w  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(102)

基本上,目标是能够采用如下结构:

struct Test
{
    id : i64,
    name : String,
    data : HashMap<String, String>,
}

然后让宏返回一个字段类型的元组,按照我们声明test字段的顺序,如下所示:所以它可以用在下面的上下文中,例如scylla::IntoTypedRows;

rows.into_typed::<(get_field_types!(Test))>()

而不是目前的方式,即:

rows.into_typed::<(i64, String, HashMap<String, String>)>()

这样,当结构变得更大时,它不会变得乏味或庞大。
我遇到的问题是,我能够返回一个Vec<&str>,但似乎无法解释如何让它完成上述任务。这是我的尝试:

macro_rules! get_field_types {
    ($struct_name:ty) => {
        {
            let mut field_types = Vec::new();
            let _ = <$struct_name>::default(); // Ensure the struct is instantiated
            let field_values = stringify!($struct_name {
                $(field: _type,)*
                ..
            });
            let field_pairs = field_values.split(',').filter_map(|field_value| {
                let field_type = field_value.split_whitespace().nth(1)?;
                Some(field_type.trim_end_matches(',').trim())
            });
            field_types.extend(field_pairs);
            field_types
        }
    };
}
ctehm74n

ctehm74n1#

PitaJ在这里是正确的,你应该使用#[derive(FromRow)]rows.into_typed::<Test>()来做这件事,因为它节省了维护宏的麻烦,并使你的结构更灵活。
本着学习的精神,下面是如何使用声明性宏来实现这一点。虽然宏目前还不能做查找(如果它们能做的话,我会很惊讶),但你可以像这样在结构声明中应用它们:

use paste::paste;

macro_rules! field_tuple {
        (
            $vis_:vis struct $name:ident {
                $($fvis_:vis $it:ident : $typ:ty, )*
            }
        ) => {
            $vis_ struct $name {
                $($fvis_ $it: $typ),*
            }
            
            paste! {
                $vis_ type [<$name FieldTypes>] = ($($typ),*);
            }
        };
}

enum Color {
    Pink,
    Blue,
    Black,
    White,
}

field_tuple!(struct Penguin {
    pub height: u32,
    pub(crate) weight: u8,
    color: Color,
});

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn compiles() {
        let _: PenguinFieldTypes;
    }
}

它使用paste crate来连接结构名称和FieldTypes来生成类型定义,这样你就可以用它来定义多个字段元组类型,而不会相互冲突。

相关问题