Rust宏系列教程—实现复杂派生宏

《Rust宏系列教程—自定义派生宏》博客中,我们详细介绍自定义派生宏的过程。但演示例子相对简单,本文在前面基础上实现更复杂、更强大的派生宏示例。并且还提供更好的方法使用迭代器和quote,我在最初的实现中跳过了这一点——这是有意为之,因为它需要我们学习更多的 quote语法。

前文示例代码优化

在我们深入研究它的工作原理之前,让我们看看它会是什么样子:

let input = syn::parse_macro_input!(item as syn::DeriveInput);
    let struct_identifier = &input.ident;

    match &input.data {
   
        Data::Struct(syn::DataStruct {
    fields, .. }) => {
   
            let field_identifiers = fields.iter().map(
                |item| item.ident.as_ref().unwrap()
            ).collect::<Vec<_>>();
            
            quote! {
   
                impl From<#struct_identifier> for std::collections::HashMap<String, String> {
   
                    fn from(value: #struct_identifier) -> Self {
   
                        let mut hash_map = std::collections::HashMap::<String, String>::new();

                        #(
                            hash_map.insert(
                                stringify!(#field_identifiers).to_string(),
                                String::from(value.#field_identifiers));
                        )*
                        
                        hash_map
                    }
                }
            }
        }
        _ => unimplemented!()
    }.into()

这看起来更简洁,更容易理解!让我们来看看使它成为可能的特殊语法——特别是下面这行:

#(
    hash_map.insert( stringify!(#field_identifiers).to_string(), String::from(value.#field_identifiers) );
)*

让我们来分析一下。首先,用#()*将整个代码块包装起来,然后将代码放入括号内。这种语法允许你使用圆括号内的任何迭代器,并且它将为迭代器中的所有项重复该代码块,同时在每次迭代中将变量替换为正确的项。

在本例中,首先创建一个field_identifiers迭代器,它是目标结构中所有字段标识符的集合。然后,在直接使用迭代器时编写hash_map插入语句,就好像它是单个项一样。#()*包装器将其转换为预期的多行输出,每一行代表迭代器中的每一项。
在这里插入图片描述

更复杂派生宏示例

我们已经掌握了轻松地编写简单的派生宏技能,接下来,是时候继续创建在现实世界中实际有用的东西了—特别是在使用数据库模型的情况下。

  • 构建DeriveCustomModel<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值