Rust中实现依赖泛型方法的外部Trait时,如何表达方法的Trait约束?
通用问题
我有一个结构体,其impl块中的泛型方法带有类型约束。在实现外部trait时,我希望依赖该方法的存在。
Rust中是否存在某种变通方案,允许在impl层面表达泛型方法的限制?
我设想这类似针对类型而非生命周期的高阶Trait约束(Higher Ranked Trait Bounds),即“对所有类型B,条件都必须成立”。
伪代码示例:
struct A{}; impl A { fn constrained<B,F>(p : F) where F : Fn(A)->B, SomeConstraint<B>{ ... } } impl SomeTrait for A where "the method constrained() exists" { ... }
编辑:看来并非只有我需要此功能。近期已有一项重大变更提案(Major Change Proposal):Add experimental support for for<T> binders in limited positions。相关实现工作已启动,Implement partial support for non-lifetime binders已在数日前合并。
具体问题场景
我正在使用higher库,尝试基于它实现Free Monad类型。这主要是为了学习Rust泛型,无实际业务场景,且我希望仅用泛型而非宏实现。
如前文所述,我现在有一个类型,其泛型方法需要基于自身类型参数的Trait约束。我想在实现外部trait(例如Functor)时使用该方法,但无法在当前层面合理表达该方法的Trait约束。
以下是我已实现的可编译代码:
enum Free<'a,A,F> where F : Functor<'a,Never>{ Pure(A), Free(Box<F::Target<Self>>) } impl<'a,A,G> Free<'a,A,G> where G : Functor<'a,Never>{ fn __fmap_impl<B, F>(self, f: &'a F) -> Free<'a,B,G> where F: Fn(A) -> B + 'a, G::Target::<Self> : Functor<'a, Self, Target<Free<'a,B,G>>> = G::Target<Free<'a,B,G>>>{ match self { Free::Pure(a) => {Free::Pure(f(a))}, Free::Free(fa) => { Free::<'a,B,G>::Free(Box::new( fa.fmap(|x| x.__fmap_impl(f)) )) }, } } }
使用Never是为了避免Free类型出现无限递归……我利用Functor的关联类型GAT将Never替换为它实际包装的类型。
我当前面临的问题是__fmap_impl()方法的约束。
当尝试为Free实现实际的Functor trait时,我无法正确表达该约束:
impl<'a,A,G> Functor<'a,A> for Free<'a,A,G> where G:Functor<'a,Never>{ type Target<T> = Free<'a,T,G>;; fn fmap<B, F>(self, f: F) -> Self::Target<B> where F: Fn(A) -> B + 'a, G::Target::<Self> : Functor<'a, Self, Target<Free<'a,B,G>>> = G::Target<Free<'a,B,G>>>{ self.__fmap_impl(&f) } }
编译报错:
error[E0276]: impl has stricter requirements than trait
我无法将约束从fmap方法移至impl块,因为此时B类型未知;若强行添加B,则会出现:
error[E0207]: the type parameter
Bis not constrained by the impl trait, self type, or predicates
impl<'a,A,B,G> Functor<'a,A> for Free<'a,A,G> where G:Functor<'a,Never>, G::Target::<Self> : Functor<'a, Self, Target<Free<'a,B,G>>> = G::Target<Free<'a,B,G>>>{ type Target<T> = Free<'a,T,G>;; fn fmap<C, F>(self, f: F) -> Self::Target<C> where F: Fn(A) -> C + 'a { self.__fmap_impl(&f) } }
如果能针对类型使用高阶Trait约束,上述问题即可解决,因为对于行为良好的Functor,约束条件G:Functor<'a,Never>, G::Target::<Self> : Functor<'a, Self, Target<Free<'a,B,G>>> = G::Target<Free<'a,B,G>>>应对所有可能的类型B成立(除非我的理解有误)……
我猜想自己可能选错了解决问题的角度,欢迎任何相关的解决方案建议。
内容的提问来源于stack exchange,提问作者soulsource

