实现 returns 通用的特征函数
Implementing a trait function that returns generic
在下面的代码中,名为 LimitCollection 的特征有一个函数,return是一个实现 Iterator 特征的类型。
struct Limit {}
impl Limit {
fn is_violated(&self) -> bool {
todo!()
}
}
trait LimitCollection {
fn get_violated_limits<'a, I>(&'a self) -> I
where
I: Iterator<Item = &'a Limit>;
}
现在我想做一些实现特征的东西,但编译器抱怨我 return 的类型与通用 return 类型不匹配:“预期类型参数 I
, 找到结构 Filter
"
struct ConcreteLimitCollection {
limits: Vec<Limit>,
}
impl LimitCollection for ConcreteLimitCollection {
fn get_violated_limits<'a, I>(&'a self) -> I
where
I: Iterator<Item = &'a Limit>,
{
self.limits.iter().filter(Limit::is_violated)
}
}
有没有什么方法可以使这个构造工作,最好不求助于动态分配?
通常你会使用关联类型,在这种情况下我们会涉及一些生命周期(我们需要 GAT,通用关联类型)。可悲的是,它所需要的还没有稳定下来:
#![feature(generic_associated_types)]
struct Limit {}
impl Limit {
fn is_violated(&self) -> bool {
todo!()
}
}
trait LimitCollection {
type Output<'a>: Iterator<Item = &'a Limit> where Self: 'a;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a>;
}
struct ConcreteLimitCollection {
limits: Vec<Limit>,
}
impl LimitCollection for ConcreteLimitCollection {
type Output<'a> = Box<dyn Iterator<Item = &'a Limit> + 'a> where Self: 'a;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a> {
Box::new(self.limits.iter().filter(|l| l.is_violated()))
}
}
免责声明,即使您不想使用动态分配,我也使用了 Box<dyn Iterator<Item = &'a Limit> + 'a>
,但在这种情况下,您只需要完成整个 Filter<...>
类型。为了简单起见,只是使用了 Boxed 迭代器。
@SvenMarnach 适合这些类型
:
impl LimitCollection for ConcreteLimitCollection {
type Output<'a> = std::iter::Filter<std::slice::Iter<'a, Limit>, fn(&&Limit) -> bool>;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a> {
self.limits.iter().filter(|l| l.is_violated())
}
}
Is there any way to make this construct work, preferably without resorting to dynamic allocation?
泛型意味着调用者决定类型是什么,因为I
(类型)是一个输入参数所以调用者应该能够传入只要满足约束,他们想要的就可以。
但这里不是这样的,你让来电者别无选择。
给调用者别无选择,但给trait implementer一个选择的方法是关联类型。
可悲的是,正如 Netwave 指出的那样,这里需要通用关联类型(因为 Iterator
在 'a
生命周期内是通用的),并且 GAT 不稳定。
有两种方法可以参数化特征本身,并为引用而不是类型实现特征。 有各种可能性的示例和讨论。
在下面的代码中,名为 LimitCollection 的特征有一个函数,return是一个实现 Iterator 特征的类型。
struct Limit {}
impl Limit {
fn is_violated(&self) -> bool {
todo!()
}
}
trait LimitCollection {
fn get_violated_limits<'a, I>(&'a self) -> I
where
I: Iterator<Item = &'a Limit>;
}
现在我想做一些实现特征的东西,但编译器抱怨我 return 的类型与通用 return 类型不匹配:“预期类型参数 I
, 找到结构 Filter
"
struct ConcreteLimitCollection {
limits: Vec<Limit>,
}
impl LimitCollection for ConcreteLimitCollection {
fn get_violated_limits<'a, I>(&'a self) -> I
where
I: Iterator<Item = &'a Limit>,
{
self.limits.iter().filter(Limit::is_violated)
}
}
有没有什么方法可以使这个构造工作,最好不求助于动态分配?
通常你会使用关联类型,在这种情况下我们会涉及一些生命周期(我们需要 GAT,通用关联类型)。可悲的是,它所需要的还没有稳定下来:
#![feature(generic_associated_types)]
struct Limit {}
impl Limit {
fn is_violated(&self) -> bool {
todo!()
}
}
trait LimitCollection {
type Output<'a>: Iterator<Item = &'a Limit> where Self: 'a;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a>;
}
struct ConcreteLimitCollection {
limits: Vec<Limit>,
}
impl LimitCollection for ConcreteLimitCollection {
type Output<'a> = Box<dyn Iterator<Item = &'a Limit> + 'a> where Self: 'a;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a> {
Box::new(self.limits.iter().filter(|l| l.is_violated()))
}
}
免责声明,即使您不想使用动态分配,我也使用了 Box<dyn Iterator<Item = &'a Limit> + 'a>
,但在这种情况下,您只需要完成整个 Filter<...>
类型。为了简单起见,只是使用了 Boxed 迭代器。
@SvenMarnach 适合这些类型 :
impl LimitCollection for ConcreteLimitCollection {
type Output<'a> = std::iter::Filter<std::slice::Iter<'a, Limit>, fn(&&Limit) -> bool>;
fn get_violated_limits<'a>(&'a self) -> Self::Output<'a> {
self.limits.iter().filter(|l| l.is_violated())
}
}
Is there any way to make this construct work, preferably without resorting to dynamic allocation?
泛型意味着调用者决定类型是什么,因为I
(类型)是一个输入参数所以调用者应该能够传入只要满足约束,他们想要的就可以。
但这里不是这样的,你让来电者别无选择。
给调用者别无选择,但给trait implementer一个选择的方法是关联类型。
可悲的是,正如 Netwave 指出的那样,这里需要通用关联类型(因为 Iterator
在 'a
生命周期内是通用的),并且 GAT 不稳定。
有两种方法可以参数化特征本身,并为引用而不是类型实现特征。