8

I'm trying to return a slice from a vector which is built inside my function. Obviously this doesn't work because v's lifetime expires too soon. I'm wondering if there's a way to extend v's lifetime. I want to return a plain slice, not a vector.

pub fn find<'a>(&'a self, name: &str) -> &'a[&'a Element] {
    let v: Vec<&'a Element> = self.iter_elements().filter(|&elem| elem.name.borrow().local_name == name).collect();
    v.as_slice()
}
SBSTP
  • 3,479
  • 6
  • 30
  • 41

1 Answers1

4

You can't forcibly extend a value's lifetime; you just have to return the full Vec. If I may ask, why do you want to return the slice itself? It is almost always unnecessary, since a Vec can be cheaply (both in the sense of easy syntax and low-overhead at runtime) coerced to a slice.

Alternatively, you could return the iterator:

use std::iter;

pub fn find<'a>(&'a self, name: &str) -> Box<Iterator<Item = &'a Element> + 'a> {
    Box::new(self.iter_elements()
       .filter(move |&elem| elem.name.borrow().local_name == name))
}

For now, you will have to use an iterator trait object, since closure have types that are unnameable.

NB. I had to change the filter closure to capture-by-move (the move keyword) to ensure that it can be returned, or else the name variable would just passed into the closure pointer into find's stack frame, and hence would be restricted from leaving find.

huon
  • 94,605
  • 21
  • 231
  • 225
  • I wanted to return a read-only list. I guess what I'd need is an OwnedSlice, but that's probably just Vec. I can't return an iterator, because I want it to be indexable. – SBSTP Mar 02 '15 at 23:15
  • 1
    Since the `Vec` (or whatever) contains `&Elements` the actual contents of the list is as read-only as it would be with a `&[]`. Returning a `Vec` rather than a `&[]` effectively just allows the user to modify the length of that vector (e.g. `push`/`pop` elements from it), restricting that is usually unnecessary especially in Rust, where `Vec`s etc. are uniquely owned, so changing a `Vec` doesn't change any values anywhere else. – huon Mar 03 '15 at 00:02
  • Also, you can return an iterator: if the user absolutely needs to randomly-access it more than once, then they can manually `.collect()`. If they only wish to iterate in order, or index randomly once (possible via `nth`) then returning the iterator is likely to be more efficient, as the elements will only be generated on demand. Of course, if the structure is *usually* randomly-accessed, then requiring `collect` will just make things more verbose. (I just realised I made a mistake with the iterator suggestion as written. Fixing.) – huon Mar 03 '15 at 00:04