How to specify a slice lifetime in a trait?


#1

I’m having trouble figuring out how to specify the lifetime of a slice. My code looks like this:

pub trait MyContainer<T> {
    fn get(index: u64) -> Result<T, Error>;
    fn get_range(start: u64, end: u64) -> Result<&[T], Error>;
    fn set(index: u64, data: T) -> Result<MyContainer<T>, Error>;
    fn set_range(index: u64, data: &[T]) -> Result<MyContainer<T>, Error>;
}

It’ll basically store a list of T, in a functional way such that any modification results in a new MyContainer<T>. The goal of get_range is to return a slice from this MyContainer’s list. I get a lifetime error here, of course, and that makes sense–I’m returning a reference, I have to say how long it will live. Intuitively, I think it makes sense for the slice to live as long as the MyContainer object, so I try adding a lifetime parameter:

pub trait MyContainer<'a, T> {
    ...
    fn get_range(start: u64, end: u64) -> Result<&'a [T], Error>;
    ...
}

…But then I get an error for all the other functions returning MyContainer<T>, complaining that I’m not passing in a lifetime parameter:

   |
15 |     fn set(index: u64, data: T) -> Result<MyContainer<T>, Error>;
   |                                           ^^^^^^^^^^^^^^ expected lifetime parameter
   |
   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
   = help: consider giving it an explicit bounded or 'static lifetime

It seems like if I were to define the other functions like this:

pub trait MyContainer<'a, T> {
    ...
    fn set(index: u64, data: T) -> Result<MyContainer<'a, T>, Error>;
    ...
}

Then what I’m saying is: I want all returned MyContainers to have the same lifetime as myself. Is that correct? I definitely don’t want that, I want them to have a lifetime of their own. I don’t see where I can get another lifetime from.

How do I specify a lifetime for the returned slice (since that really is referring to my internal allocated memory), but not for the MyContainers?


#2

Your trait methods need a parameter for the instance of the object you’re dealing with, either self, &self, or &mut self. Your get methods should probably be &self, and set methods &mut self. Then you’ll get an implicit lifetime from this parameter to the return type, or you can make it explicit like:

fn get_range<'a>(&'a self, start: u64, end: u64) -> Result<&'a [T], Error>;

#3

Ah! That makes sense. Thanks.