Lifetimes with struct field referencing a slice of a type

Hi,

I just for the first time tried to deal with lifetimes and I am struggling.

I have a struct Bar that refers to a slice of a type implementing a given trait:

pub trait Foo {
    fn print_foo(&self) {
        println!("Hello from Foo");
    }
}

#[derive(Clone)]
pub struct MyStruct {}

impl MyStruct {
    pub fn new() -> Self { MyStruct {} }
}

impl Foo for MyStruct {}

pub struct Bar<'a, T: Foo> {
    data: &'a [T]
}

impl<'a, T> Bar<'a, T>
where
T: Foo
{
    pub fn new(bars: &'a [T]) -> Self {
        Bar { data: bars }
    }
    pub fn prints(&self) {
        for elt in self.data.iter() {
            elt.print_foo();
        }
    }
}

//pub fn default_with_size(size: usize) -> Bar {
//    let my_vec = vec![MyStruct::new(); size];
//    Bar::new(&my_vec)
//}

fn main() {
    let my_vec = vec![MyStruct::new(); 3];
    let bars = Bar::new(&my_vec);
    //let bars = default_with_size(3);
    bars.prints();
}

Running this code gives the expected output, however if I uncomment the definition of the default_with_size() function, i get two compilation errors that I don't understand:

  • error[E0106]: missing lifetime specifier. help: consider giving it an explicit bounded or 'static lifetime: Bar + 'static
  • error[E0107]: wrong number of type arguments: expected 1, found 0. expected 1 type argument

I have the feeling that this error result from the fact that my_vec is dropped at the end of the call to the function and hence cannot outlive it, which is problematic as the struct Bar refers to it.
Is this the actual reason explaining why the code does not compile ? Also, how can iI change my code to make it work ?

Thanks in advance !

The problem here is that default_with_size() returns Bar, but Bar isn't a type, it is a family of types parametrised by a type T and a lifetime 'a. T should be MyStruct in default_with_size(), so the return type (without lifetimes) is Bar<MyStruct>.

Figuring out what the lifetime parameter should be raises another problem, which is that there are no input lifetimes to bind the output lifetime to. The returned reference is a reference to a local vector, which will be deallocated when the function returns, leaving the reference dangling. Rust won't allow that. Functions like that thus can't exist. Structs with references are referencing existing data, so there aren't usually functions to produce such values out of nowhere.

So, from your input, I should rather implement a macro to provide the default values rather than a function.

If what you want is to provide a function that produces a Bar<'static, MyStruct>, then you could write a macro for that, or you could do it as a function using the unstable const generics feature. However, it may be just as short to write Bar::new(&[MyStruct; size]).

A more important question to ask is whether you need Bar to contain a reference in the first place, if the default value doesn't really borrow from anything external. Why not just store a Vec<T> in Bar instead?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.