Frustratingly advanced lifetime/generic situation


#1

So I’m doing something very tricky that involes generics and references. Essentially, I want to make a struct that not only takes a generic parameter, but contains a field of its recursive type (ie. a tree node with a child that’s a reference to another tree node with the same generic type specified). Rust complicates things, in that regard. I cannot find an answer to this that doesn’t involve someone also using a trait type.

Despite my best efforts to adhere to the compiler, this is as good as I can get and Rust still complains:

struct A<'a, T: 'a>
{
    f: Option<&'a A<'a, T>>, // in C++, this would be either A<T>& or A<T>*
}

impl<'a, T> A<'a, T>
{
    fn get(&mut self, p: &'a T) // likewise, A::get(T p) in C++
    {
        self.f = Some(p);
    }
}

fn main()
{
    let u = 9u32;
    let p = 8u32;
    let b = A::<u32> { f: None };
    let mut a = A::<u32> { f: Some(&b) };
    a.get(&p);
}

When I test out how to do stuff in Rust, I tend to use the online compiler with a “trivial” example. This example makes the compiler spit out “T is an unused parameter”. I have a feeling maybe I don’t even know how this works in Rust.


#2

It sounds like you’re wanting to make a generic linked list. One of the problems you’ll have with that implementation is internal mutability and the compiler not letting you change something once it’s been added to your linked list.

Have you read Learning Rust With Entirely Too Many Linked Lists? Even if it doesn’t address your exact problem, that guide teaches you a lot about these more advanced applications of generics and lifetimes.

Also, is there any particular reason why you need to be using references instead of letting the datastructure own the data?


#3

The compiler seems correct here in that you aren’t using the parameter T. You do in fact have a reference to a A<T>, but T is never actually used anywhere. T needs to be stored somehow. Your struct seems to want to store two pieces of information: T and an optional reference to the next struct. Here is a quick fix:

#[derive(Debug)]
struct A<'a, T: 'a>
{
    data: T, // in C++, this would be either A<T>& or A<T>*
    next: Option<&'a A<'a, T>>,
}

impl<'a, T> A<'a, T>
{
    fn get(&mut self, p: T) // likewise, A::get(T p) in C++
    {
        self.data = p;
    }
}

fn main()
{
    let u = 9u32;
    let p = 8u32;
    let mut a = A::<&u32> { data: &u, next: None };
    println!("{:?}", a);

    a.get(&p);
    println!("{:?}", a);
    
    let b = A::<&u32> { data: &u, next: Some(&a) };
    println!("{:?}", b);
}

#4

You know, I feel very silly now, having just woken up and realizing I could just use a Box type. I guess this is just my 4 AM logic. Haha