2
votes

I am trying to create a struct in Rust that is itself generic with respect to other generic structs. That's pretty confusing so hopefully this example will makes things clearer:

use std::ops::Deref;
use std::rc::Rc;

struct Foo<T: Deref> {
    val: T<i32>,
    other: i32,
}

impl<T> Foo<T> {
    pub fn new(&self, val: T<i32>, other: i32) -> Self {
        Foo {val: val, other: other}
    }
}

fn main() {
    let foo = Foo::new(Rc::new(0), 0);
}

playground

I would like to be able to create a Foo object by calling new with either Rc<i32> objects or Arc<i32> objects depending on whether I need thread safety or not. I get the following error when I try this though: error[E0109]: type parameters are not allowed on this type, as the compiler complains about the i32 in val: T<i32>,. Is this possible in Rust? If so, can I safely call methods on i32 assuming it will auto dereference it?

1
Unlike some other languages, unfortunately Rust doesn't (yet) have higher kinded types, so type parameters have to be concrete types. However in this case I agree with @Shepmaster that you don't need it. - Chris Emerson

1 Answers

3
votes

That syntax doesn't make sense, but this version compiles:

use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;

struct Foo<T> {
    val: T,
    other: i32,
}

impl<T> Foo<T>
    where T: Deref<Target = i32>
{
    pub fn new(val: T, other: i32) -> Self {
        Foo {
            val: val,
            other: other,
        }
    }
}

fn main() {
    let foo = Foo::new(Rc::new(0), 0);
    let foo = Foo::new(Arc::new(0), 0);
}

Note how the trait bounds read: T: Deref<Target = i32> "Any T that implements Deref with a Target of an i32".

You can then implement methods that dereference val:

fn sum(&self) -> i32 {
    *self.val + self.other
}

In general, the concept of something like

struct Foo<T> {
    val: T<i32>,
}

Wouldn't prove useful. Just because something is parameterized over a i32 doesn't mean you can do anything with that i32. Likewise, a type could be parameterized with something besides an i32 (or not at all) and still give you access to an i32.