Hierarchy type parameters

When I try to put type paramter bounds on function arguments, if the struct has a kind of hierarchy structure, the codes became very verbose.

Here is my code:

#[derive(Debug, Clone)]
struct A<T, N> {
    func: T,
    data: N
}

#[derive(Debug, Clone)]
struct B1<T, N> {
    func: T,
    data: N
}

#[derive(Debug, Clone)]
struct B2<T, N> {
    func: T,
    data: N
}

#[derive(Debug, Clone)]
struct C<T, N> {
    func: T,
    data: N
}

trait Sigs {
    fn get(&self);
}
impl<T: From<u8>, N: From<u8>, G: From<u8>, Z: From<u8>> Sigs for C<T, B1<N, A<G, Z>>> {
    fn get(&self) {
        println!("from B1");
    }
}
impl<T: From<u8>, N: From<u8>, G: From<u8>, Z: From<u8>> Sigs for C<T, B2<N, A<G, Z>>> {
    fn get(&self) {
        println!("from B2");
    }
}

Then I can use it like:

let a = A { func: 1i32, data: 1f64 };
let b1 = B1 { func: 2i32, data: a.clone() };
let b2 = B2 { func: 264, data: a.clone() };
let c1 = C { func: 1usize, data: b1.clone() };
let c2 = C { func: 1usize, data: b2.clone() };

c1.get()
from B1

c2.get()
from B2

But as can be seen above, when I implement Sigs for C<T, B>, the codes goes very long. I don't need to know what it is the type lieing in B, I just need to identity what the struct name of B.

Just like this:

impl<T: From<u8>, N: B1> Sigs for C<T, N> {
    fn get(&self) {
        println!("from B1");
    }
}
impl<T: From<u8>, N: B2> Sigs for C<T, N> {
    fn get(&self) {
        println!("from B2");
    }
}

Is there a way I can do that?

Generic bound with structs do not work.
You need to use traits to add constraints to generics.

trait Sig {
    fn foo(&self);
}

struct A<T> {
    t: T,
}

impl<T> Sig for A<T> {
    fn foo(&self) {
        println!("from a")
    }
}

struct B<U> {
    u: U,
}

impl<U> Sig for B<U> {
    fn foo(&self) {
        println!("from u")
    }
}

struct C<X, Y> {
    x: X,
    y: Y,
}

impl<X, Y: Sig> Sig for C<X, Y> {
    fn foo(&self) {
        self.y.foo()
    }
}

fn main() {
    let a = A { t: 10 };
    let b = B { u: 11 };
    let c1 = C { x: (), y: a };
    let c2 = C { x: (), y: b };
    c1.foo();
    c2.foo();
}

1 Like

I find a way to do that, but do not compile:

trait B1_ {}
impl<T, N> B1_ for B1<T, N> {}
trait B2_ {}
impl<T, N> B2_ for B2<T, N> {}

trait Sigs {
    fn get(&self);
}

impl<T: From<u8>, N: B1_> Sigs for C<T, N> {
    fn get(&self) {
        println!("from B1");
    }
}

impl<T: From<u8>, N: B2_> Sigs for C<T, N> {
    fn get(&self) {
        println!("from B2");
    }
}

[E0119] Error: conflicting implementations of trait `Sigs` for type `C<_, _>`
   โ•ญโ”€[command_6:1:1]
   โ”‚
 4 โ”‚ impl<T: From<u8>, N: B1_> Sigs for C<T, N> {
   ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  
   ยท                      โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ first implementation here
   ยท 
 9 โ”‚ impl<T: From<u8>, N: B2_> Sigs for C<T, N> {
   ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  
   ยท                      โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ conflicting implementation for `C<_, _>`
โ”€โ”€โ”€โ•ฏ

But I just implement B1_ or B2_, it works expectly:

trait Sigs {
    fn get(&self);
}
impl<T: From<u8>, N: B1_> Sigs for C<T, N> {
    fn get(&self) {
        println!("from B1");
    }
}

c1.get()
from B1

It conflicts because something could implement B1_ and B2_.

These shorter versions of your OP work:

impl<T, U, N> Sigs for C<T, B1<U, N>> {
    fn get(&self) {
        println!("from B1");
    }
}

impl<T, U, N> Sigs for C<T, B2<U, N>> {
    fn get(&self) {
        println!("from B2");
    }
}

But if there's a goal beyond typing less, I'm not understanding what it is.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.