如何编写实现通用特征 fx 的过程宏。添加?
How to write a procedural macro that implements a generic trait, fx. Add?
我有一个 Module
特征,我想编写一个程序宏来实现 Add
、Sub
和 Mul
以实现 Module
特征。
给定一个实现 Module
的结构 Foo<S>
,生成的代码应该如下所示
impl <S, RHS: Module> std::ops::Add<RHS> for Foo<S> {
type Output = crate::modules::Add<Foo<S>, RHS>;
fn add(self, rhs: RHS) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
问题在于 struct 和 Add
trait 都有自己的泛型类型。
如果不是这种情况,宏代码可能看起来像这样
let name = &ast.ident;
let generics = &ast.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote! {
impl #impl_generics std::ops::Add<RHS> for #name #ty_generics #where_clause {
type Output = crate::modules::Add<#name, RHS>;
fn add(self, rhs: RHS) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
}
但是 RHS
类型从未定义过。
我尝试了 <#impl_generics, RHS: Module>
等变体,但其中 none 有效。
显然,为 T: Module
全面实施 Add
会更好,但这是不可能的,因为不能为类型参数实施外部特征。参见 here。解决此问题的方法也可以解决我在这种特定情况下的问题,但似乎我所问的应该是可能的。
有什么办法吗?
我不确定为什么你的宏代码不起作用,但更简单的方法是为任何实现 Module
的 T
编写一个全面的实现,并完全避免使用宏:
impl<T, Rhs> std::ops::Add<Rhs> for T
where
T: Module,
Rhs: Module,
{
type Output = crate::modules::Add<T, Rhs>;
fn add(self, rhs: Rhs) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
解决方案是手动处理 Foo 的类型参数,而不是使用 generics.split_for_impl()
。
我上面的例子的工作版本变成了。
let name = &ast.ident;
let generics = &ast.generics;
let type_params = generics.type_params();
let (_, ty_generics, where_clause) = generics.split_for_impl();
quote! {
#ast // This is not a derive macro, sp this is necessary to keep the original struct definition.
impl <#(#type_params),*, RHS: crate::modules::Module> std::ops::Add<RHS> for #name #ty_generics #where_clause {
type Output = crate::modules::Add<#name #ty_generics, RHS>;
fn add(self, rhs: RHS) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
}
其中 type_params
是具有边界的类型参数的迭代器,#(#type_params),*,
创建这些类型参数的列表。
我有一个 Module
特征,我想编写一个程序宏来实现 Add
、Sub
和 Mul
以实现 Module
特征。
给定一个实现 Module
的结构 Foo<S>
,生成的代码应该如下所示
impl <S, RHS: Module> std::ops::Add<RHS> for Foo<S> {
type Output = crate::modules::Add<Foo<S>, RHS>;
fn add(self, rhs: RHS) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
问题在于 struct 和 Add
trait 都有自己的泛型类型。
如果不是这种情况,宏代码可能看起来像这样
let name = &ast.ident;
let generics = &ast.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote! {
impl #impl_generics std::ops::Add<RHS> for #name #ty_generics #where_clause {
type Output = crate::modules::Add<#name, RHS>;
fn add(self, rhs: RHS) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
}
但是 RHS
类型从未定义过。
我尝试了 <#impl_generics, RHS: Module>
等变体,但其中 none 有效。
显然,为 T: Module
全面实施 Add
会更好,但这是不可能的,因为不能为类型参数实施外部特征。参见 here。解决此问题的方法也可以解决我在这种特定情况下的问题,但似乎我所问的应该是可能的。
有什么办法吗?
我不确定为什么你的宏代码不起作用,但更简单的方法是为任何实现 Module
的 T
编写一个全面的实现,并完全避免使用宏:
impl<T, Rhs> std::ops::Add<Rhs> for T
where
T: Module,
Rhs: Module,
{
type Output = crate::modules::Add<T, Rhs>;
fn add(self, rhs: Rhs) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
解决方案是手动处理 Foo 的类型参数,而不是使用 generics.split_for_impl()
。
我上面的例子的工作版本变成了。
let name = &ast.ident;
let generics = &ast.generics;
let type_params = generics.type_params();
let (_, ty_generics, where_clause) = generics.split_for_impl();
quote! {
#ast // This is not a derive macro, sp this is necessary to keep the original struct definition.
impl <#(#type_params),*, RHS: crate::modules::Module> std::ops::Add<RHS> for #name #ty_generics #where_clause {
type Output = crate::modules::Add<#name #ty_generics, RHS>;
fn add(self, rhs: RHS) -> Self::Output {
crate::modules::Add::new(self, rhs)
}
}
}
其中 type_params
是具有边界的类型参数的迭代器,#(#type_params),*,
创建这些类型参数的列表。