面试题答案
一键面试- 宏定义框架:
#[proc_macro_derive(SumFields)] pub fn sum_fields_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse(input).expect("Failed to parse input"); let struct_name = &ast.ident; let fields = match ast.fields { syn::Fields::Named(ref fields) => &fields.named, _ => panic!("Only named fields are supported"), }; let field_accessors: Vec<String> = fields.iter().map(|field| { format!("self.{}", field.ident.as_ref().unwrap()) }).collect(); let sum_expression = field_accessors.join(" + "); let gen = quote! { impl #struct_name { pub fn sum_fields(&self) -> Self::Item { #sum_expression } } }; gen.into() }
- 处理泛型参数:
- 在这个宏中,假设结构体是类似
struct MyStruct<T> { field1: T, field2: T }
这样的形式(只有一种泛型类型且所有字段都是该泛型类型)。 - 为了确保宏在不同数值类型上都能正确工作,需要依赖 Rust 的 trait 约束。因为要进行加法操作,所以泛型参数
T
必须实现std::ops::Add
trait 以及Copy
trait(方便直接进行值相加而不是移动所有权)。可以在生成的impl
块中添加这些约束。修改后的gen
如下:
这样,当使用这个let gen = quote! { impl<T: std::ops::Add<Output = T> + Copy> #struct_name<T> { pub fn sum_fields(&self) -> T { #sum_expression } } };
derive
宏时,Rust 编译器会检查泛型参数是否满足这些约束,从而保证sum_fields
方法在不同数值类型上都能正确工作。例如i32
、f64
等类型都实现了Add
和Copy
,所以可以正常使用。 - 在这个宏中,假设结构体是类似