第一件事:我想实现什么
我试图将Iterator::fold()
与本身就是Iterator
的累加器一起使用,但除此之外,我还需要在内部克隆该迭代器。
fn whatever<T,U,V,W>(some_iterator : T, other_cloneable_iterator_init : U) -> impl Iterator<Item=W>
where T: Iterator<Item=V>,
U: Iterator<Item=W>+Clone
{
some_iterator.fold(other_cloneable_iterator_init,|other_cloneable_iterator, value| {
let computed_value =
some_function_that_consumes_an_iterator(other_cloneable_iterator.clone(), value);
other_iterator.filter(|other_value| some_function(computed_value, other_value))
}
}
这当然不能像上面写的那样工作,因为给fold
的闭包的返回类型与初始值设定项的类型不同。
为什么这个问题会导致这个问题
然而,它们的共同点是,它们都实现了Iterator<Item=W>+Clone
特性。这几乎尖叫着";通过使该类型成为特征对象来擦除该类型";。
如果这只是Iterator<Item=W>
的特征,我会这么做。然而,Clone
特性不是对象安全的。正在搜索";克隆装箱特征对象";在线上产生了各种讨论,这些讨论要么需要特征对象上的'static
生存期(Iterators
通常没有(,要么使用不安全的代码(我想避免(,比如dyn克隆箱。
实际问题:
因此,如果希望避免使用不安全的代码,并且没有获得'static
生存期的奢侈,那么如何为装箱的trait对象实现Clone
呢?我说的是下面这样的代码,它有生存期问题,不能编译:
trait Cu32Tst<'a> : Iterator<Item=u32>+'a {
fn box_clone(&self) -> Box<dyn Cu32Tst+'a>;
}
impl<'a, T : Iterator<Item=u32>+Clone+'a> Cu32Tst<'a> for T {
fn box_clone(&self) -> Box<dyn Cu32Tst+'a> {
Box::new(self.clone())
}
}
impl<'a> Clone for Box<dyn Cu32Tst<'a>>{
fn clone(&self) -> Self {
self.box_clone()
}
}
我希望在Box
本身上使用Clone
的原因是,为了将其用作累加器类型,我必须能够从Iterator::filter()
方法的输出中创建一个新的Box<dyn IteratorTraitObject>
,如果调用它的迭代器是Clone
,则该方法仅为Clone
(然后我还必须为Box
实现Iterator
,但这可以直接转发到包含的值(。
长话短说:Clone
可以为有限寿命的特征对象实现吗?如果可以,如何实现?
您需要修改代码以实现Box<dyn Cu32Tst<'a>>
而不是Box<dyn Cu32Tst + 'a>
。后者可能实现了Cu32Tst<'static>
,这不是您想要的Cu32Tst<'a>
的Clone
的一揽子实现。这编译:
trait Cu32Tst<'a>: Iterator<Item = u32> + 'a {
fn box_clone(&self) -> Box<dyn Cu32Tst<'a>>;
}
impl<'a, T: Iterator<Item = u32> + Clone + 'a> Cu32Tst<'a> for T {
fn box_clone(&self) -> Box<dyn Cu32Tst<'a>> {
Box::new(self.clone())
}
}
impl<'a> Clone for Box<dyn Cu32Tst<'a>> {
fn clone(&self) -> Self {
self.as_ref().box_clone()
}
}
游乐场
注意,Clone
实现使用self.as_ref().box_clone()
调用box_clone()
。这是因为Cu32Tst
的blanket impl与Box<dyn Cu32Tst>
匹配,因为它既是Clone
又是Iterator
,所以盒子本身获得了box_clone()
方法。因此,self.box_clone()
将进行编译,但会导致无限递归。