Почему реализация черты не компилируется для структуры, но компилируется для ссылки на структуру? - PullRequest
2 голосов
/ 18 апреля 2019

Чтобы ответить на один из моих предыдущих вопросов ( Как реализовать универсальный признак с помощью универсального типа, реализующего Iterator? ), мне был передан этот кусок кода:

pub trait Vector {
    type Item;
    type Iter: Iterator<Item = Self::Item>;

    // several functions
    fn iter(&self) -> Self::Iter;
}

pub struct VectorImplementation1<T> {
    numbers: Vec<T>,
}

impl<'a, T> Vector for &'a VectorImplementation1<T> {
    type Item = &'a T;
    type Iter = std::slice::Iter<'a, T>;

    fn iter(&self) -> Self::Iter {
        self.numbers.iter()
    }
}

fn main() {}

Я вижу, что эта черта реализована для ссылки на структуру, и она не компилируется, если я использую только структуру.Может кто-нибудь объяснить, почему?

1 Ответ

0 голосов
/ 19 апреля 2019

Проблема здесь, как упомянуто ошибкой компилятора, состоит в том, что время жизни 'a не имеет причин быть там, если оно реализовано так:

impl<'a, T> Vector for VectorImplementation1<T> {
    /**/
}
error[E0207]: the lifetime parameter `'a` is not constrained by the impl 
trait, self type, or predicates
  --> src/main.rs:13:6
   |
13 | impl<'a, T> Vector for VectorImplementation1<T> {
   |      ^^ unconstrained lifetime parameter

Потому что в этом случае компилятор смотрит только на определение, а не на тело. Другой подход, который, вероятно, не был упомянут ранее для простоты, заключается в следующем:

pub trait Vector<'a> {
    type Item: 'a;
    type Iter: Iterator<Item = Self::Item> + 'a;

    // several functions
    fn iter(&'a self) -> Self::Iter;
}

pub struct VectorImplementation1<T> {
    numbers: Vec<T>,
}

impl<'a, T: 'a> Vector<'a> for VectorImplementation1<T> {
    type Item = &'a T;
    type Iter = std::slice::Iter<'a, T>;

    fn iter(&'a self) -> Self::Iter {
        self.numbers.iter()
    }
}

impl<'a, T: 'a> Vector<'a> for &'a VectorImplementation1<T> {
    type Item = &'a T;
    type Iter = std::slice::Iter<'a, T>;

    fn iter(&'a self) -> Self::Iter {
        self.numbers.iter()
    }
}

В этом случае мы перемещаем время жизни в признак, чтобы признак мог «использовать» время жизни и, следовательно, проверял использование нами реализации признака. Но, как я упоминал ранее, в этом есть дополнительная сложность, связанная с необходимостью понимания времени жизни, связанного с этой чертой, что снижает читабельность.

...