Почему это приведение к объекту черты, кажется, меняет семантику заимствования? - PullRequest
4 голосов
/ 14 апреля 2019

Редактировать: В более ранней версии этого я сделал ссылку на 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,
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...