是否可以为具有有限生命周期的特征对象实现克隆(不使用不安全代码)?

Can Clone be implemented for a trait object with finite lifetime (without using unsafe code)?

要事第一:我要实现什么目标?

我正在尝试将 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的闭包的return类型与初始化器的类型不同。

为什么这个问题会导致这个问题?

然而,它们的共同点是都实现了 Iterator<Item=W>+Clone 特性。这几乎是在尖叫“通过使类型成为特征对象来擦除类型”。

如果它只是 Iterator<Item=W> 特质,我就会那样做。但是,Clone 特性不是对象安全的。在线搜索“clone boxed trait object”会产生各种讨论,所有讨论都 on the trait object (what Iterators usually do not have), or using unsafe code (which I would like to avoid) like the dyn-clone crate。

实际问题:

因此,如果想避免使用不安全代码,并且没有获得 'static 生命周期的奢侈,那么如何为装箱特征对象实现 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 的原因是,为了将其用作累加器类型,我必须能够从输出中创建一个新的 Box<dyn IteratorTraitObject> Iterator::filter() 方法的方法,如果调用它的迭代器是 Clone,则它只是 Clone(然后我必须为 Box 实现 Iterator 作为好吧,但这可以转发到包含的值)。

长话短说:可以 Clone 为具有有限生命周期的特征对象实现吗?如果可以,如何实现?

您需要修改代码以实现 Box<dyn Cu32Tst<'a>> 而不是 Box<dyn Cu32Tst + 'a>。后者大概实现了 Cu32Tst<'static>,这不是你想要的 CloneCu32Tst<'a> 的全面实现。这编译:

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()
    }
}

Playground

请注意,Clone 实现使用 self.as_ref().box_clone() 调用 box_clone()。这是因为 Cu32Tst 的整体实现与 Box<dyn Cu32Tst> 相匹配,因为它既是 Clone 又是 Iterator,所以盒子本身有一个 box_clone() 方法。结果,self.box_clone() 可以编译,但会导致无限递归。