为什么强制转换为特征对象似乎改变了借用语义?

时间:2019-04-14 17:51:32

标签: rust traits lifetime borrow-checker

编辑:在此的较早版本中,我提到了GAT,这可能会使注意力从问题的意图中转移出来。我已经编辑了代码,以删除一种关联的类型并从整体上简化了它。我想从这个问题中了解什么:

为什么rustc接受装箱的对象作为具体类型,却在将同一个对象转换为装箱的特征时抱怨呢?我可以进行哪些更改以使盒装特征版本被接受?

我要定义的特征大致是:

  

可以创建某种迭代器的事物,该事物可以借用该事物并迭代其寿命大于该事物但不一定等于'static的生命周期的值。

经过一番努力,我终于可以将其与一个简单的引用实现结构(请参见CreatesIterator)一起编写起来(请参见IteratorWithRef)。这个具体的实现有效-它创建了指定样式的迭代器,可以迭代。如果我将此实现转换为特征对象,则借用检查器会将我关闭:

error[E0597]: `*creates_iterator_dyn` does not live long enough
  --> src/main.rs:17:17
   |
17 |         let _ = creates_iterator_dyn.iterate().count();
   |                 ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
18 |     }
   |     -
   |     |
   |     `*creates_iterator_dyn` dropped here while still borrowed
   |     borrow might be used here, when `creates_iterator_dyn` is dropped and runs the destructor for type `std::boxed::Box<dyn CreatesIterator<'_, '_, IteratorWithRef<'_, '_>>>`

Rust Playground

以及下面的代码。

type LongTraitObjType<'collection, 'data> =
    Box<dyn CreatesIterator<'collection, 'data, IteratorWithRef<'collection, 'data>> + 'data>;

fn main() {
    let data = 1;

    // Works: concrete implementation:
    {
        let creates_iterator_impl = Box::new(CreatesIteratorImpl(vec![Wrapper(&data)]));
        let _ = creates_iterator_impl.iterate().count();
    }

    // Doesn't work: same as above, but cast to a trait object.
    {
        let creates_iterator_dyn: LongTraitObjType =
            Box::new(CreatesIteratorImpl(vec![Wrapper(&data)]));
        let _ = creates_iterator_dyn.iterate().count();
    }
}

#[derive(Clone)]
struct Wrapper<'data>(&'data u32);

struct IteratorWithRef<'collection, 'data: 'collection> {
    reference: &'collection CreatesIteratorImpl<'data>,
    i: usize,
}
impl<'collection, 'data: 'collection> Iterator for IteratorWithRef<'collection, 'data> {
    type Item = Wrapper<'data>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.i < self.reference.0.len() {
            let ret = Some(self.reference.0[self.i].clone());
            self.i += 1;
            ret
        } else {
            None
        }
    }
}

trait CreatesIterator<'collection, 'data, E>
where
    'data: 'collection,
    E: Iterator + 'collection,
    <E as Iterator>::Item: 'data,
{
    fn iterate(&'collection self) -> E;
}

struct CreatesIteratorImpl<'data>(Vec<Wrapper<'data>>);

impl<'collection, 'data: 'collection>
    CreatesIterator<'collection, 'data, IteratorWithRef<'collection, 'data>>
    for CreatesIteratorImpl<'data>
{
    fn iterate(&'collection self) -> IteratorWithRef<'collection, 'data> {
        IteratorWithRef {
            reference: self,
            i: 0,
        }
    }
}

0 个答案:

没有答案