1

I'm running into an issue with lifetimes in rust that I'm having trouble figuring out. I've tried a lot of tweaks to the below but I keep introducing new errors. I want index to return a Vector object.

I have:

struct Matrix<T> {
    num_rows: i32,
    num_cols: i32,
    data: Vec<T>
}

struct Vector<T> {
    data: Vec<T>
}

And I'm trying to do

impl<T: Clone> Index<usize> for Matrix<T> {
    type Output = Vector<T>;

    fn index(&self, i: usize) -> &Vector<T> {
        let index = i as i32;
        let start = (index * &self.num_cols) as usize;
        let end = (((index + 1) * &self.num_cols) - 1) as usize;
        let data_slice = &self.data[start..end];
        let data = data_slice.to_vec();
        let vector_temp = Vector::<T>::new(data);
        return &vector_temp;
    }
}

But I'm getting

error: `vector_temp` does not live long enough
  --> src\main.rs:45:17
   |
45 |         return &vector_temp;
   |                 ^^^^^^^^^^^ does not live long enough
46 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on        the block at 38:44...
  --> src\main.rs:38:45
   |
38 |     fn index(&self, i: usize) -> &Vector<T> {
   |                                             ^

 error: aborting due to previous error

 error: Could not compile `hello_world`.

I haven't fully grokked lifetimes in rust yet so was hoping someone could help me out. Thanks!

user5534715
  • 55
  • 2
  • 6

1 Answers1

3

You're trying to return a reference to an object that will be destroyed once the function ends. vector_temp will no longer exist once index returns and so returning a reference to it is illegal (because that reference would point to nowhere).

What you want to do, is return the slice you're creating and let the caller decide what to do with it:

impl<T: Clone> Index<usize> for Matrix<T> {
    type Output = [T];

    fn index(&self, i: usize) -> &[T] {
        let index = i as i32;
        let start = (index * &self.num_cols) as usize;
        let end = (((index + 1) * &self.num_cols) - 1) as usize;

        &self.data[start..end]
    }
}

You can then have the caller do what you did in your original implementation:

let m1 = Matrix { ... };
let owned_vector = m1[index_here].to_owned();

I am not 100% sure where you go from here, given I'm not sure how much further you're going to take this. Returning the unsized slice can have its problems and so without knowing your specific use case I'm not sure if there is a better way you could handle this.

Hopefully this helps with your immediate issue though.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138