2

To answer one of my previous questions (How to implement a generic trait with a generic type implementing Iterator?), this chunk of code was given to me:

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

I see that the trait is implemented for a reference of struct, and it doesn't compile if I use only a struct. Can someone explain why?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • I believe your question is answered by the answers of [Is there any way to return a reference to a variable created in a function?](https://stackoverflow.com/q/32682876/155423) and/or [How do I write an iterator that returns references to itself?](https://stackoverflow.com/q/30422177/155423). If you disagree, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Apr 18 '19 at 23:36
  • TL;DR — If you took `self` and did `impl Vector for VectorImplementation1`, then the vector would go out of scope and the reference could never be valid. If you took `&self` and did `impl Vector for VectorImplementation1`, then you'd be trying to tie the reference of the returned value to a lifetime you can't name. – Shepmaster Apr 18 '19 at 23:38

1 Answers1

0

The problem here, as mentioned by the compiler error, is that the lifetime 'a has no reason to be there if it is implemented like so:

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

Because the compiler only looks at the definition, and not the body in this case. A different approach, which probably wasn't mentioned earlier for simplicity, is the following:

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

In this case, we move the lifetime to the trait, so that the trait can "use" the lifetime, and therefore validate our use of the trait implementation. But as I mentioned earlier, this has the added complexity of needing to understand the lifetimes attached to this trait, reducing readability.

Optimistic Peach
  • 3,862
  • 2
  • 18
  • 29