JacopoStanchi
JacopoStanchi

Reputation: 2136

Create a slice of slice with sufficient lifetime

I have a function foo that takes in parameter an array slice of array slices, however I can't seem to create a variable that lives long enough to pass it as a parameter:

fn main() {
    let mut outer_vec = vec![];
    for i in 0..10 {
        let inner_vec = vec![i];
        outer_vec.push(inner_vec.as_slice());
    }
    foo(&outer_vec);
}

fn foo(_bar: &[&[u8]]) {
    println!("foo");
}

I get this error:

error[E0597]: `inner_vec` does not live long enough
 --> src/main.rs:5:24
  |
5 |         outer_vec.push(inner_vec.as_slice());
  |                        ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
6 |     }
  |     - `inner_vec` dropped here while still borrowed
7 |     foo(&outer_vec);
  |         ---------- borrow later used here

I know that a given inner array slice cannot outlive the lifetime of the inner_vec it originates from, which is dropped at the end of the for loop, but I want to know if it is possible to fix this error without changing the signature of the foo function, that is, keep it foo(_bar: &[&[u8]]) and not change it to something like foo(_bar: &[Vec<u8>]).

Thank you for your help.

Upvotes: 0

Views: 256

Answers (3)

realkstrawn93
realkstrawn93

Reputation: 796

You could use Vec::leak() and a turbofish to force the slice to live forever:

let vec_of_slices =
    outer_vec.iter()
    .map(|inner_vec| inner_vec.leak::<'static>())
    .collect::<Vec<_>>();

One downside to this, of course, is that, as the name of the leak() method suggests, you’d be leaking memory by doing this.

Also note that Vec::leak() returns a mutable slice — if you need an immutable slice, you can instead use slice::from_raw_parts():

let vec_of_slices =
    outer_vec.iter()
    .map(|inner_vec| unsafe {
        use core::mem::ManuallyDrop;
   
        let inner_vec = ManuallyDrop::new(inner_vec);
        
        core::slice::from_raw_parts::<'static>(
            inner_vec.as_ptr(),
            inner_vec.len()
        )
    })
    .collect::<Vec<_>>();

Note that this call to slice::from_raw_parts() needs to be marked unsafe since it deals with raw pointers. This is really a duplication of how Vec::leak() is defined, only in the upstream case slice::from_raw_parts_mut() is used.

Upvotes: 0

JacopoStanchi
JacopoStanchi

Reputation: 2136

To keep the same signature for foo, you can create a variable that keeps the ownership of the inner_vecs and create slices from it in another variable:

fn main() {
    let mut outer_vec = vec![];
    for i in 0..10 {
        let inner_vec = vec![i];
        outer_vec.push(inner_vec);
    }
    let vec_of_slices: Vec<&[u8]> = outer_vec.iter()
        .map(|inner_vec| inner_vec.as_slice()).collect();
    foo(&vec_of_slices);
}

fn foo(_bar: &[&[u8]]) {
    println!("foo");
}

Upvotes: 1

Aleksander Krauze
Aleksander Krauze

Reputation: 6061

Your problem has nothing to do with function foo. It exists inside for loop. Comment out calling foo and you will still have an error. In every iteration you create local variable inner_vec that is dropped at the end of the iteration. You therefore cannot store a reference to it that would escape the for loop. In other words it's lifetime is to short.

The solution here would be to give the ownership of inner_vec to outer_vec by moving it (not the reference). Then you would have to change foo's signature as well.

Upvotes: 1

Related Questions