基本完备的builder macro
自己手动实现得一个基本 derive builder macro
use std::{any::Any, ops::Deref};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{Data, DataStruct, DeriveInput, Fields};
#[proc_macro_derive(Builder)]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// let i = input.clone();
// let ast = syn::parse(input).unwrap();
let ast = syn::parse_macro_input!(input as DeriveInput);
match impl_builder_macro(&ast) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}
fn impl_builder_macro(ast: &syn::DeriveInput) -> Result<proc_macro::TokenStream, syn::Error> {
let name = &ast.ident;
let vis = &ast.vis;
let generics = &ast.generics;
// 确保宏应用在结构体上
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
// todo: 添加对 tuple struct 的支持
_ => {
return Err(syn::Error::new_spanned(
ast,
"Builder can only be derived for structs with named fields",
))
}
};
// 生成 builder 结构体的字段
let fields_builder = fields.iter().map(|f| {
let vis = &f.vis;
let name = &f.ident;
let ty = &f.ty;
if is_option_type(ty) {
quote! {
#vis #name: #ty
}
} else {
quote! {
#vis #name: Option<#ty>
}
}
});
// 创建一个没有 bounds 的泛型
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let builder_struct = format_ident!("{}Builder", name);
let builder_struct_def = match where_clause {
Some(where_clause) => quote! {
#vis struct #builder_struct #ty_generics #where_clause {
#(#fields_builder),*
}
},
None => quote! {
#vis struct #builder_struct #ty_generics {
#(#fields_builder),*
}
},
};
// 为每个 field 生成 setter 方法
let setter_methods = fields.iter().map(generate_setter_methods);
// 生成 new 方法的 fields
let new_fields = fields.iter().map(|f| {
let name = &f.ident;
quote! {
#name: None
}
});
// 生成 build 方法的 fields
let build_fields = fields.iter().map(|f| {
let name = &f.ident;
let ty = &f.ty;
if is_option_type(ty) {
// 对于 Option 类型的字段,直接使用 builder 中的值
quote! {
#name: self.#name
}
} else {
// 对于非 Option 类型的字段,使用 ok_or_else 解包
quote! {
#name: self.#name.ok_or_else(|| format!("字段 {} 缺失", stringify!(#name)))?
}
}
});
let builder_struct_impl = quote! {
impl #builder_struct {
// 创建新的构建器,所有字段初始为 None
#vis fn new() -> Self {
Self {
#(#new_fields),*
}
}
// 为每个 field 生成 setter 方法
#(#setter_methods)*
// build 方法,构建最终结构体
#vis fn build(self) -> Result<#name, String> {
Ok(#name {
#(#build_fields),*
})
}
}
};
// 为原始结构体生成 builder 方法
let original_struct_impl = quote! {
impl #name {
#vis fn builder() -> #builder_struct {
#builder_struct::new()
}
}
};
let final_gen = quote! {
#builder_struct_def
#builder_struct_impl
#original_struct_impl
};
Ok(final_gen.into())
}
fn generate_setter_methods(field: &syn::Field) -> TokenStream {
let vis = &field.vis;
let name = &field.ident;
let ty = &field.ty;
if is_string_type(ty) {
// 仅对简单的 String 类型使用 AsRef<str>
quote! {
#vis fn #name<T>(mut self, value: T) -> Self
where
T: AsRef<str>,
{
self.#name = Some(value.as_ref().to_string());
self
}
}
} else if is_vec_string_type(ty) {
// 对 Vec<String> 类型使用接收 IntoIterator<Item = impl AsRef<str>> 的泛型方法
quote! {
#vis fn #name<I, T>(mut self, value: I) -> Self
where
I: IntoIterator<Item = T>,
T: AsRef<str>,
{
self.#name = Some(value.into_iter().map(|s| s.as_ref().to_string()).collect());
self
}
}
} else if is_option_type(ty) {
// 对 Option<_> 类型使用接收 Into<_> 的泛型方法
let inner_ty = inner_option_type(ty);
match inner_ty {
Some(inner_type) => quote! {
#vis fn #name<T>(mut self, value: T) -> Self
where
T: Into<#inner_type>,
{
self.#name = Some(value.into());
self
}
},
None => quote! {
#vis fn #name<T>(mut self, value: T) -> Self
where
T: Into<#inner_ty>,
{
self.#name = Some(None);
self
}
},
}
} else {
// 对其他类型使用原始类型
quote! {
#vis fn #name<T>(mut self, value: #ty) -> Self
where
T: Into<#ty>,
{
self.#name = Some(value);
self
}
}
}
}
// 辅助函数:检查是否是 String 类型
#[inline]
fn is_string_type(ty: &syn::Type) -> bool {
__is_type_equal(ty, "String")
}
// 辅助函数:检查是否是 Vec<String> 类型
#[inline]
fn is_vec_string_type(ty: &syn::Type) -> bool {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == "Vec" {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
return is_string_type(inner_ty);
}
}
}
}
}
false
}
// 辅助函数:检查是否是 Option 类型
#[inline]
fn is_option_type(ty: &syn::Type) -> bool {
__is_type_equal(ty, "Option")
}
#[inline]
fn __is_type_equal(ty: &syn::Type, expected_type: &str) -> bool {
match ty {
syn::Type::Path(ty_path) => ty_path
.path
.segments
.last()
.map_or_else(|| false, |s| s.ident == expected_type),
_ => false,
}
}
#[inline]
fn inner_option_type(ty: &syn::Type) -> Option<&syn::Type> {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == "Option" {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
return Some(inner_ty);
}
}
}
}
}
None
}
找 AI 提的意见和建议
Rust Builder
宏的重构与优化
看了你的代码实现,我发现你已经构建了一个相当完善的 Builder 宏,它能处理不同类型的字段并为它们生成适当的 setter 方法。我将分析你的代码,提出一些优化建议,并解释为什么这些改进是有益的。
代码分析与优化建议
1. 错误处理改进
你已经将错误处理添加到了 derive
函数中,这很好!但是在一些子函数中,我们可以进一步增强错误处理能力。
// 改进错误处理,在所有可能失败的地方返回 Result
fn impl_builder_macro(ast: &syn::DeriveInput) -> Result<TokenStream, syn::Error> {
// ... 已有代码 ...
// 在每个可能失败的步骤使用 ? 操作符
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => {
return Err(syn::Error::new_spanned(
ast,
"Builder 只能用于具有命名字段的结构体"
))
}
};
// ... 其余代码 ...
}
为什么:更细粒度的错误处理可以提供更具体的错误信息,帮助用户更快地定位问题。使用 syn::Error::new_spanned
能够在编译时精确地指向问题代码。
2. 类型检查逻辑优化
你已经实现了对常见类型(如 String
、Vec<String>
和 Option<T>
)的处理,但这些类型检查函数可以更加模块化和健壮。
// 更加健壮的类型检查函数
fn is_type_with_name(ty: &syn::Type, name: &str) -> bool {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
return segment.ident == name;
}
}
false
}
fn is_parametrized_type(ty: &syn::Type, outer_name: &str, inner_name: &str) -> bool {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == outer_name {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
return is_type_with_name(inner_ty, inner_name);
}
}
}
}
}
false
}
// 简化调用
fn is_string_type(ty: &syn::Type) -> bool {
is_type_with_name(ty, "String")
}
fn is_vec_string_type(ty: &syn::Type) -> bool {
is_parametrized_type(ty, "Vec", "String")
}
fn is_option_type(ty: &syn::Type) -> bool {
is_type_with_name(ty, "Option")
}
为什么:这种方法使类型检查更加模块化,减少代码重复,同时也使代码更易于维护和扩展。如果将来需要支持其他复合类型,可以很容易地添加新的组合。
3. 对泛型和关联类型的完善支持
你已经添加了对泛型的支持,这很好!但我们可以更进一步完善对泛型约束的处理。
// 在生成 Builder 实现时处理泛型
fn impl_builder_macro(ast: &syn::DeriveInput) -> Result<TokenStream, syn::Error> {
let name = &ast.ident;
let vis = &ast.vis;
let generics = &ast.generics;
// 创建一个没有 bounds 的泛型
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
// ... 其余代码 ...
// 为 Builder 结构体生成实现,包含泛型参数
let builder_struct_impl = quote! {
impl #impl_generics #builder_struct #ty_generics #where_clause {
// ... 方法实现 ...
}
};
// 为原始结构体生成 builder 方法
let original_struct_impl = quote! {
impl #impl_generics #name #ty_generics #where_clause {
#vis fn builder() -> #builder_struct #ty_generics {
#builder_struct::new()
}
}
};
// ... 其余代码 ...
}
为什么:正确处理泛型参数和约束可以确保生成的代码与原始结构体具有相同的类型约束,避免编译错误并保持类型安全。
4. 优化 setter 方法生成
你的 setter 方法生成已经很好了,但我们可以进一步优化它们以提供更好的用户体验,特别是对于转换类型的处理。
fn generate_setter_methods(field: &syn::Field) -> TokenStream {
let vis = &field.vis;
let name = &field.ident;
let ty = &field.ty;
let name_str = name.as_ref().unwrap().to_string();
// 为每种类型生成文档注释
let doc_comment = format!("/// 设置 `{}` 字段的值", name_str);
let doc_attr = quote! { #[doc = #doc_comment] };
if is_string_type(ty) {
// 字符串类型
quote! {
#doc_attr
#vis fn #name<T: AsRef<str>>(mut self, value: T) -> Self {
self.#name = Some(value.as_ref().to_string());
self
}
}
} else if is_vec_string_type(ty) {
// Vec<String> 类型
quote! {
#doc_attr
#vis fn #name<I, T>(mut self, value: I) -> Self
where
I: IntoIterator<Item = T>,
T: AsRef<str>,
{
self.#name = Some(value.into_iter().map(|s| s.as_ref().to_string()).collect());
self
}
}
} else if is_option_type(ty) {
// Option<T> 类型
let inner_ty = extract_type_from_option(ty);
quote! {
#doc_attr
#vis fn #name<T>(mut self, value: Option<T>) -> Self
where
T: Into<#inner_ty>,
{
self.#name = value.map(Into::into);
self
}
}
} else {
// 其他类型
quote! {
#doc_attr
#vis fn #name<T: Into<#ty>>(mut self, value: T) -> Self {
self.#name = Some(value.into());
self
}
}
}
}
为什么:这种改进增加了文档注释,使 API 更加用户友好。同时,使用泛型约束(如 AsRef<str>
、Into<T>
等)增加了 API 的灵活性,允许用户使用多种兼容类型。
5. 添加属性支持
一个强大的宏系统通常允许用户通过属性自定义行为。我们可以添加对 #[builder(...)]
属性的支持。
#[proc_macro_derive(Builder, attributes(builder))]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// ... 已有代码 ...
}
// 解析字段上的 builder 属性
fn parse_builder_attributes(field: &syn::Field) -> BuilderFieldAttributes {
let mut attrs = BuilderFieldAttributes {
optional: false,
default: None,
};
for attr in &field.attrs {
if attr.path.is_ident("builder") {
// 解析 #[builder(...)] 属性内容
if let Ok(nested) = attr.parse_meta() {
if let syn::Meta::List(list) = nested {
for item in list.nested.iter() {
if let syn::NestedMeta::Meta(meta) = item {
if meta.path().is_ident("optional") {
attrs.optional = true;
} else if meta.path().is_ident("default") {
// 解析默认值
if let syn::Meta::NameValue(name_value) = meta {
if let syn::Lit::Str(lit_str) = &name_value.lit {
let tokens = lit_str.value().parse::<TokenStream>().unwrap_or_default();
attrs.default = Some(syn::parse2::<syn::Expr>(tokens).unwrap_or_else(|_| {
syn::parse_quote!(Default::default())
}));
}
}
}
}
}
}
}
}
}
attrs
}
struct BuilderFieldAttributes {
optional: bool,
default: Option<syn::Expr>,
}
为什么:属性支持使宏更加灵活,允许用户自定义生成代码的行为。例如,#[builder(optional)]
可以标记可选字段,#[builder(default = "...")]
可以提供默认值。
6. 改进 build 方法中的错误处理
为了提供更好的用户体验,我们可以改进 build
方法中的错误处理,使用自定义错误类型并提供更详细的错误信息。
// 生成 build 方法的代码
let build_fields = fields.iter().map(|f| {
let name = &f.ident;
let ty = &f.ty;
let attrs = parse_builder_attributes(f);
if attrs.optional || is_option_type(ty) {
// 对于可选字段或 Option 类型的字段
if let Some(default_expr) = attrs.default {
quote! {
#name: self.#name.unwrap_or_else(|| #default_expr)
}
} else {
quote! {
#name: self.#name
}
}
} else {
// 对于必需字段
let name_str = name.as_ref().unwrap().to_string();
quote! {
#name: self.#name.ok_or_else(|| BuildError::MissingField(#name_str.to_string()))?
}
}
});
// 生成自定义错误类型
let error_type = quote! {
#[derive(Debug)]
pub enum BuildError {
MissingField(String),
}
impl std::fmt::Display for BuildError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::MissingField(field) => write!(f, "Missing required field: {}", field),
}
}
}
impl std::error::Error for BuildError {}
};
// 在 build 方法中使用自定义错误类型
let build_method = quote! {
pub fn build(self) -> Result<#name #ty_generics, BuildError> {
Ok(#name {
#(#build_fields),*
})
}
};
为什么:自定义错误类型提供了更细粒度的错误处理,使用户能够更容易地识别和处理构建过程中可能出现的错误。
7. 实现 Default trait
为了提高用户体验,我们可以为 Builder 实现 Default
trait。
let builder_struct_def = quote! {
#[derive(Default)]
#vis struct #builder_struct #ty_generics #where_clause {
#(#fields_builder),*
}
};
为什么:实现 Default
trait 使用户可以通过 MyStructBuilder::default()
创建 builder 实例,这是一种常见的 Rust 惯用法。
完整优化后的实现
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
parse_quote, Data, DataStruct, DeriveInput, Fields, GenericParam, Generics, Ident, Type,
Visibility,
};
/// Builder 宏的入口函数
#[proc_macro_derive(Builder, attributes(builder))]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(input as DeriveInput);
match impl_builder_macro(&ast) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// 实现 Builder 宏的主要逻辑
fn impl_builder_macro(ast: &DeriveInput) -> Result<TokenStream, syn::Error> {
let name = &ast.ident;
let vis = &ast.vis;
let generics = &ast.generics;
// 创建一个没有 bounds 的泛型
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
// 获取 Builder 结构体名称
let builder_struct = format_ident!("{}Builder", name);
// 确保宏应用在结构体上
let fields = match &ast.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => {
return Err(syn::Error::new_spanned(
ast,
"Builder 只能用于具有命名字段的结构体",
))
}
};
// 生成 Builder 结构体的字段
let fields_builder = fields.iter().map(|f| {
let vis = &f.vis;
let name = &f.ident;
let ty = &f.ty;
let attrs = parse_builder_attributes(f);
// 处理可选字段和 Option 类型
if attrs.optional || is_option_type(ty) {
if is_option_type(ty) {
// Option 类型保持不变
quote! {
#vis #name: #ty
}
} else {
// 非 Option 类型但标记为可选
quote! {
#vis #name: Option<#ty>
}
}
} else {
// 必需字段
quote! {
#vis #name: Option<#ty>
}
}
});
// 定义 Builder 结构体
let builder_struct_def = quote! {
#[derive(Default)]
#vis struct #builder_struct #ty_generics #where_clause {
#(#fields_builder),*
}
};
// 为每个字段生成 setter 方法
let setter_methods = fields.iter().map(generate_setter_methods);
// 生成构建错误类型
let build_error_type = quote! {
/// Builder 过程中可能发生的错误
#[derive(Debug)]
#vis enum BuilderError {
/// 表示缺少必需字段
MissingField(String),
}
impl std::fmt::Display for BuilderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::MissingField(field) => write!(f, "缺少必需字段: {}", field),
}
}
}
impl std::error::Error for BuilderError {}
};
// 生成 new 方法的字段初始化
let new_fields = fields.iter().map(|f| {
let name = &f.ident;
let attrs = parse_builder_attributes(f);
let ty = &f.ty;
if let Some(default_expr) = &attrs.default {
// 使用默认值
quote! {
#name: #default_expr
}
} else if is_option_type(ty) {
// Option 类型默认为 None
quote! {
#name: None
}
} else {
// 其他类型默认为 None
quote! {
#name: None
}
}
});
// 生成 build 方法的字段
let build_fields = fields.iter().map(|f| {
let name = &f.ident;
let name_str = name.as_ref().unwrap().to_string();
let ty = &f.ty;
let attrs = parse_builder_attributes(f);
if attrs.optional {
// 可选字段
quote! {
#name: self.#name
}
} else if is_option_type(ty) {
// Option 类型字段
quote! {
#name: self.#name
}
} else {
// 必需字段,使用自定义错误
quote! {
#name: self.#name.ok_or_else(|| BuilderError::MissingField(#name_str.to_string()))?
}
}
});
// 实现 Builder 方法
let builder_struct_impl = quote! {
impl #impl_generics #builder_struct #ty_generics #where_clause {
/// 创建一个新的构建器实例
#vis fn new() -> Self {
Self {
#(#new_fields),*
}
}
// 为每个字段生成 setter 方法
#(#setter_methods)*
/// 构建最终的结构体实例
///
/// 如果缺少必需字段,将返回错误
#vis fn build(self) -> Result<#name #ty_generics, BuilderError> {
Ok(#name {
#(#build_fields),*
})
}
}
};
// 为原始结构体实现 builder 方法
let original_struct_impl = quote! {
impl #impl_generics #name #ty_generics #where_clause {
/// 创建一个新的构建器
#vis fn builder() -> #builder_struct #ty_generics {
#builder_struct::new()
}
}
};
// 组合所有生成的代码
let final_gen = quote! {
#build_error_type
#builder_struct_def
#builder_struct_impl
#original_struct_impl
};
Ok(final_gen)
}
/// 为字段生成 setter 方法
fn generate_setter_methods(field: &syn::Field) -> TokenStream {
let vis = &field.vis;
let name = &field.ident;
let ty = &field.ty;
let name_str = name.as_ref().unwrap().to_string();
let attrs = parse_builder_attributes(field);
// 生成文档注释
let doc_comment = format!("/// 设置 `{}` 字段的值", name_str);
let doc_attr = quote! { #[doc = #doc_comment] };
if is_option_type(ty) {
// 处理 Option<T> 类型
let inner_ty = extract_type_from_option(ty).unwrap_or_else(|| {
// 如果无法提取内部类型,使用 () 作为默认
syn::parse_quote!(())
});
quote! {
#doc_attr
#vis fn #name<T>(mut self, value: T) -> Self
where
T: Into<#inner_ty>,
{
self.#name = Some(Some(value.into()));
self
}
/// 将 `#name` 字段设置为 None
#vis fn #name_none(mut self) -> Self {
self.#name = Some(None);
self
}
}
} else if is_string_type(ty) {
// 处理 String 类型
quote! {
#doc_attr
#vis fn #name<T: AsRef<str>>(mut self, value: T) -> Self {
self.#name = Some(value.as_ref().to_string());
self
}
}
} else if is_vec_string_type(ty) {
// 处理 Vec<String> 类型
quote! {
#doc_attr
#vis fn #name<I, T>(mut self, value: I) -> Self
where
I: IntoIterator<Item = T>,
T: AsRef<str>,
{
self.#name = Some(value.into_iter().map(|s| s.as_ref().to_string()).collect());
self
}
}
} else if is_vec_type(ty) {
// 处理其他 Vec<T> 类型
let inner_ty = extract_type_from_vec(ty).unwrap_or_else(|| {
// 如果无法提取内部类型,使用 () 作为默认
syn::parse_quote!(())
});
quote! {
#doc_attr
#vis fn #name<I, T>(mut self, value: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<#inner_ty>,
{
self.#name = Some(value.into_iter().map(Into::into).collect());
self
}
}
} else {
// 处理其他类型
quote! {
#doc_attr
#vis fn #name<T: Into<#ty>>(mut self, value: T) -> Self {
self.#name = Some(value.into());
self
}
}
}
}
/// 解析字段上的 builder 属性
fn parse_builder_attributes(field: &syn::Field) -> BuilderFieldAttributes {
let mut attrs = BuilderFieldAttributes {
optional: false,
default: None,
};
for attr in field.attrs.iter().filter(|a| a.path.is_ident("builder")) {
// 解析 #[builder(...)] 属性
let nested = match attr.parse_meta() {
Ok(syn::Meta::List(meta)) => meta.nested,
_ => continue,
};
for meta in nested {
match meta {
syn::NestedMeta::Meta(syn::Meta::Path(path)) if path.is_ident("optional") => {
attrs.optional = true;
}
syn::NestedMeta::Meta(syn::Meta::NameValue(name_value))
if name_value.path.is_ident("default") =>
{
if let syn::Lit::Str(lit_str) = &name_value.lit {
// 解析默认值表达式
let tokens = lit_str.value().parse::<TokenStream>().unwrap_or_default();
attrs.default = syn::parse2::<syn::Expr>(tokens).ok();
}
}
_ => {}
}
}
}
// 如果字段是 Option 类型,自动将其标记为可选
if is_option_type(&field.ty) {
attrs.optional = true;
}
attrs
}
/// 表示 builder 字段属性
struct BuilderFieldAttributes {
/// 字段是否可选
optional: bool,
/// 字段的默认值
default: Option<syn::Expr>,
}
/// 检查类型是否为 String
fn is_string_type(ty: &syn::Type) -> bool {
is_type_with_name(ty, "String")
}
/// 检查类型是否为 Vec<String>
fn is_vec_string_type(ty: &syn::Type) -> bool {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == "Vec" {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
return is_string_type(inner_ty);
}
}
}
}
}
false
}
/// 检查类型是否为 Vec<T>
fn is_vec_type(ty: &syn::Type) -> bool {
is_type_with_name(ty, "Vec")
}
/// 检查类型是否为 Option<T>
fn is_option_type(ty: &syn::Type) -> bool {
is_type_with_name(ty, "Option")
}
/// 检查类型是否与给定名称匹配
fn is_type_with_name(ty: &syn::Type, name: &str) -> bool {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
return segment.ident == name;
}
}
false
}
/// 从 Option<T> 中提取 T 类型
fn extract_type_from_option(ty: &syn::Type) -> Option<syn::Type> {
extract_type_from_generic(ty, "Option")
}
/// 从 Vec<T> 中提取 T 类型
fn extract_type_from_vec(ty: &syn::Type) -> Option<syn::Type> {
extract_type_from_generic(ty, "Vec")
}
/// 从泛型类型中提取内部类型
fn extract_type_from_generic(ty: &syn::Type, outer_name: &str) -> Option<syn::Type> {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == outer_name {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
// 克隆内部类型
return Some(inner_ty.clone());
}
}
}
}
}
None
}
优化说明与设计理念
1. 模块化和代码重用
我重构了代码以采用更加模块化的设计,将相关功能分组到独立的函数中。这不仅使代码更易于理解,还减少了重复代码,提高了可维护性。例如,我创建了通用的类型检查函数 is_type_with_name
和泛型类型提取函数 extract_type_from_generic
,这些可被多个特定类型函数重用。
2. 增强的错误处理
原代码已经有了一些错误处理,但我进一步完善了它,为用户提供更清晰、更有用的错误消息。使用 syn::Error::new_spanned
可以精确地指向问题代码,让用户更容易定位和修复问题。同时,自定义 BuilderError
类型使错误报告更加具体和有意义。
3. 属性支持与可配置性
我添加了对 #[builder(...)]
属性的支持,使宏更加灵活可配置。用户现在可以通过属性来:
- 标记可选字段
#[builder(optional)]
- 指定默认值
#[builder(default = "...")]
这极大地增强了宏的灵活性,使用户可以根据自己的需求自定义生成代码的行为。
4. 改进的类型处理
原代码已经对 String
、Vec<String>
和 Option<T>
等类型有特殊处理,但还可以更进一步:
- 为
Option<T>
类型增加了field_none()
方法,方便设置为None
- 改进了对
Vec<T>
的处理,不仅限于Vec<String>
- 统一了类型检查和提取逻辑,使代码更加一致和可理解
5. 更好的文档与用户体验
为生成的代码添加了文档注释,这使 API 更易于发现和使用。同时,通过实现 Default
trait 和提供更多便捷方法,改善了用户体验,使 Builder 模式的使用更加符合 Rust 的习惯。
6. 泛型与约束的完善处理
改进的代码更好地处理了泛型参数和约束,确保生成的代码与原始结构体具有相同的泛型参数和约束...