可以为具有有限生存期的特征对象实现克隆吗(不使用不安全的代码)



第一件事:我想实现什么

我试图将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()将进行编译,但会导致无限递归。

相关内容

最新更新