Search code examples
genericsreferencerustany

Generic struct with a reference to the same type but with any concrete type


My intention is to create a struct that holds a reference to another one of a similar type, but with different generics to be used as a chain of linked objects.

The problem is that writing this using the _ placeholder is not allowed:

the type placeholder `_` is not allowed within types on item
signatures

E0121

I cannot simply give my struct another type parameter since the referenced object may reference another object too, and so on. This would lead to a very large number of type parameters, which is not practical.

I would like to find a way to change this implementation to make it work:

// The type parameters are:
// O: this Router's data type
// B: The parent router's data type
pub struct DataRouter<'a, O, B = O>
where
    O: 'a,
    B: 'a,
{
    parent: Option<&'a DataRouter<'a, B, _>>, // Here the problem `_`
    range: Option<Range<usize>>,
    data: Option<O>,
}

I can't simply put a parameter here as I would've to add it to the struct, which then would cause the same infinite loop of adding a type parameter.

Is there a way to hold a reference to a DataRouter with B data type which itself holds a reference to a parent DataRouter with an unknown data type? The struct has to know only the direct parent data type, not the one of the second parent.

If this cannot be fixed, can you suggest a different implementation that could work?


Solution

  • Since you don't (and indeed cannot) care about the type of the parent's parent, introduce abstraction through a trait:

    trait Parent {}
    
    struct Nil;
    impl Parent for Nil {}
    
    pub struct DataRouter<'a, T, P>
    where
        P: 'a,
    {
        parent: Option<&'a P>,
        data: Option<T>,
    }
    
    impl<'a, T, P> Parent for DataRouter<'a, T, P> {}
    
    fn main() {
        let a = DataRouter {
            parent: None::<&'static Nil>,
            data: Some(true),
        };
        let b = DataRouter {
            parent: Some(&a),
            data: Some(42),
        };
        let c = DataRouter {
            parent: Some(&b),
            data: Some("moo"),
        };
    }