前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。 宏使用如下: #[deriv

2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。 宏使用如下: #[deriv

原创
作者头像
福大大架构师每日一题
发布2022-11-14 21:29:15
4140
发布2022-11-14 21:29:15
举报
文章被收录于专栏:福大大架构师每日一题

2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。

宏使用如下:

代码语言:rust
复制
#[derive(Builder)]
pub struct AAA {
    a: String,
    b: i32,   
    c: f64,
    d: Vec<bool>,
}

宏展开后变成如下代码:

代码语言:rust
复制
pub struct AAA {
    a: String,
    b: i32,   
    c: f64,
    d: Vec<bool>,
}
pub struct AAABuilder {
    a: std::option::Option<String>,
    b: std::option::Option<i32>,
    c: std::option::Option<f64>,
    d: std::option::Option<Vec<bool>>,
}
impl AAA {
    pub fn builder() -> AAABuilder {
        AAABuilder {
            a: std::option::Option::None,
            b: std::option::Option::None,
            c: std::option::Option::None,
            d: std::option::Option::None,
        }
    }
}

答案2022-11-14:

这题没啥技巧,自然智慧即可。

代码用rust编写。代码如下:

代码语言:rust
复制
// builder/src/lib.rs
use proc_macro::TokenStream;
use quote;
use syn::spanned::Spanned;
#[proc_macro_derive(Builder)]
pub fn derive(input: TokenStream) -> TokenStream {
    let st = syn::parse_macro_input!(input as syn::DeriveInput);
    match expand_code(&st) {
        Ok(token_stream) => token_stream.into(),
        Err(e) => e.to_compile_error().into(),
    }
}

fn get_fields(
    st: &syn::DeriveInput,
) -> syn::Result<&syn::punctuated::Punctuated<syn::Field, syn::Token![,]>> {
    if let syn::Data::Struct(syn::DataStruct {
        fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
        ..
    }) = st.data
    {
        return Ok(named);
    };
    Err(syn::Error::new_spanned(st, "必须定义在结构体上"))
}

fn gen_fields(st: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
    let fields = get_fields(st)?;
    let idents: Vec<_> = fields.iter().map(|f| &f.ident).collect();
    let types: Vec<_> = fields.iter().map(|f| &f.ty).collect();
    let ret = quote::quote!(
        #( #idents: std::option::Option<#types>),*
    );
    return Ok(ret);
}

fn gen_init_clauses(st: &syn::DeriveInput) -> syn::Result<Vec<proc_macro2::TokenStream>> {
    let fields = get_fields(st)?;
    let init_cluase: Vec<_> = fields
        .iter()
        .map(|f| {
            let ident = &f.ident;
            quote::quote!(
                #ident: std::option::Option::None
            )
        })
        .collect();
    Ok(init_cluase)
}

fn expand_code(st: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
    let struct_name_literal = st.ident.to_string();
    let builder_name_literal = format!("{}Builder", struct_name_literal);
    let builder_name_ident = syn::Ident::new(&builder_name_literal, st.span());
    let struct_ident = &st.ident;
    let builder_struct_field_def = gen_fields(st)?;
    let builder_struct_factory_init_clauses = gen_init_clauses(st)?;
    let ret = quote::quote!(
        pub struct #builder_name_ident{
            #builder_struct_field_def
        }

        impl #struct_ident {
            pub fn builder() -> #builder_name_ident {
                #builder_name_ident {
                    #(#builder_struct_factory_init_clauses),*
                }
            }
        }
    );
    Ok(ret)
}
代码语言:shell
复制
# builder.Cargo.toml
[package]
name = "derive_builder"
version = "0.0.0"
autotests = false
edition = "2021"
publish = false

[lib]
proc-macro = true

[[test]]
name = "tests"
path = "tests/progress.rs"

[dev-dependencies]
trybuild = { version = "1.0.49", features = ["diff"] }

[dependencies]
syn = {version="1.0",features=["extra-traits"]}
proc-macro2 = {version="1.0"}
quote = {version="1.0"}
代码语言:rust
复制
use derive_builder::Builder;

#[derive(Builder)]
pub struct AAA {
    a: String,
    b: i32,
    c: f64,
    d: Vec<bool>,
}

fn main() {
    let builder = AAA::builder();

    let _ = builder;
}
代码语言:shell
复制
# Cargo.toml
[package]
name = "proc-macro-workshop"
version = "0.0.0"
edition = "2021"
publish = false

[workspace]

[[bin]]
name = "workshop"
path = "main.rs"

[dependencies]
bitfield = { path = "bitfield" }
derive_builder = { path = "builder" }
derive_debug = { path = "debug" }
seq = { path = "seq" }
sorted = { path = "sorted" }

敲cargo expand命令后,打印如下:

在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档