2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。 宏使用如下: #[derive(Builder)] pub stru
2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。
宏使用如下:
#[derive(Builder)]
pub struct AAA {
a: String,
b: i32,
c: f64,
d: Vec<bool>,
}
宏展开后变成如下代码:
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编写。代码如下:
// 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)
}
# 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"}
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;
}
# 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命令后,打印如下:

2022-11-14:rust语言,请使用过程宏给结构体AAA生成结构体AAABuilder和创建AAABuilder实例的方法。 宏使用如下: #[derive(Builder)] pub stru的更多相关文章
- 2017.11.14 C语言---指针的学习
第八章 善于利用指针 (1)指针是什么 1.内存区每一个字节都有一个编号,这就是"地址".地址形象化的被称为"指针".它能通过以它为地址的内存单元.地址指向(* ...
- Rust语言之HelloWorld
Rust语言之HelloWorld 参考文档: http://doc.crates.io/guide.html 1 什么是Cargo 相当于maven/ant之于java, automake之于c, ...
- C++11/14笔记
目录 语言层面 模板表达式中的空格 nullptr和std::nullptr_t 自动推导类型----auto 一致性初始化----Uniform Initialization 初始化列表(initi ...
- 深入理解C语言的函数调用过程 【转】
转自:http://blog.chinaunix.net/uid-25909619-id-4240084.html 原文地址:深入理解C语言的函数调用过程 作者:wjlkoorey258 本文 ...
- 【转】对 Rust 语言的分析
对 Rust 语言的分析 Rust 是一门最近比较热的语言,有很多人问过我对 Rust 的看法.由于我本人是一个语言专家,实现过几乎所有的语言特性,所以我不认为任何一种语言是新的.任何“新语言”对我来 ...
- 半个月使用rust语言的体验
从第一次下载rust语言的编译器到今天刚好第14天. 简单说一下对这个语言的感觉吧. 一.性能 把以前用java写的一个中文地址切分的算法,用rust重新实现了一下(https://github.co ...
- 基数排序的可复用实现(C++11/14/17/20)
基数排序,是对整数类型的一种排序方法,有MSD (most significant digit)和LSD (least significant digit)两种.MSD将每个数按照高位分为若干个桶(按 ...
- 微软看上的Rust 语言,安全性真的很可靠吗
摘要:近几年,Rust语言以极快的增长速度获得了大量关注.其特点是在保证高安全性的同时,获得不输C/C++的性能.在Rust被很多项目使用以后,其实际安全性表现到底如何呢? 近几年,Rust语言以极快 ...
- Rust语言:安全地并发
http://www.csdn.net/article/2014-02-26/2818556-Rust http://www.zhihu.com/question/20032903 Rust是近两年M ...
- Atitit.rust语言特性 attilax 总结
Atitit.rust语言特性 attilax 总结 1. 创建这个新语言的目的是为了解决一个顽疾:软件的演进速度大大低于硬件的演进,软件在语言级别上无法真正利用多核计算带来的性能提升.1 2. 不会 ...
随机推荐
- NX1946_MoldWizard 注塑模向导建立标准库
NX1946_MoldWizard 注塑模向导建立标准库
- 微信小程序-顶部下拉菜单实现
最近写的小程序里面需要实现顶部下拉菜单的效果,做一个过滤操作,但是没有找到相关组件,所以动手写了一个. 先看一下这拙劣的效果叭~ 下面就直接看具体实现了嗷! index.wxml <view c ...
- Java 面试手撕代码
1. 判断括号有效性 public static boolean fun5(String str) { HashMap<Character, Character> hashMap = ne ...
- Jetson Xavier NX 试玩 (二)
Jetson Xavier NX 试玩 (二) Hello AI World Inference 人工智能推理模型 0 前言 想玩一玩 jetson 的人工智能功能,官方的 instructional ...
- Flutter 2 渲染原理和如何实现视频渲染
7 月 17 日下午,在前端专场巡回沙龙北京站中,声网Agora跨平台开发工程师卢旭辉带来了<Flutter2 渲染原理和如何实现视频渲染>的主题分享,本文是对演讲内容的整理. 本次分享主 ...
- 针对im输入框的一种处理方式
针对im输入框的一种处理方式 <template> <div class="chatInput"> <!-- 通过contenteditable使普通 ...
- Teamcenter_NX集成开发:通过NXOpen查询零组件是否存在
之前用过NXOpen PDM的命名空间下的类,现在记录一下通过PDM命名空间下的类查询Teamcenter零组件的信息,也可以用来判断该零组件是否存在. 1-该工程为DLL工程,直接在NX界面调用,所 ...
- 面试题锦集:1、数据库三大范式,2、mysql索引类型及作用,3、事务的特性和隔离级别
目录 面试题集锦 一.数据库三大范式 二.mysql有哪些索引类型及作用 三.事务的特性和隔离级别 1.事务的四大特性 2.事务的隔离级别 3.什么是脏读.不可重复度.幻读 4.解决办法 面试题集锦 ...
- 关于Java基础中的异常处理知识点
Java中的异常(Exception),史上最全的教程来啦~_smilehappiness的博客-CSDN博客 以及Java:详解Java中的异常(Error与Exception)_王小二(海阔天空) ...
- Charlotte Holmes series
Charlotte Holmes Novel The charactors are adorable. Jamie and Charlotte are a very cute couple. More ...