1

I'm attempting to generalize/decouple an API, so that alternative structs that satisfy a Trait can be used. Struggling on Syntax regarding nested traits. This is a stripped down example of what I'm attempting to do. Note that in the real one, there are multiple sub-traits, which potentially makes a follow-on question of "how to reduce verbosity, if I'm on the right track".

pub mod general {
    /// A trait to make the API generic
    pub trait MyTrait<A: PartialEq> {
        // type A: Partial
        fn val(self) -> A;
    }

    /// Part of the generic API
    pub struct Data<A: PartialEq, T: MyTrait<A>> {
        mys: T
    }

    /// Another part of the generic API
    fn doit<A: PartialEq>(s: impl MyTrait<A>) -> impl MyTrait {
        s
    }
}

pub mod specific {
    /// Api-specific substruct
    #[derive(PartialEq)]
    pub struct Aval {
        val: u32
    }

    /// My top-level custom struct
    pub struct MyS {
        val: Aval
    }
}

impl<A: PartialEq> crate::general::MyTrait<A> for crate::specific::MyS {
    fn val(self) -> crate::specific::Aval {
        self.val
    }
}

/// Example of how we'd use this
fn main() {
    let mys = crate::specific::MyS{ val: crate::specific::Aval{ val: 0 } };
    let S = crate::general::Data{mys};
    crate::general::doit(mys);  // Eg pretend we cloned or didn't create S.
}

Playground

In this specific example, we have a chicken+egg: Error on the Data struct of error[E0392]: parameter `A` is never used. Where if we remove A: error[E0412]: cannot find type `A` in this scope

I suspect this is a syntax problem related to associated types.

Turtles Are Cute
  • 3,200
  • 6
  • 30
  • 38
  • I don't have a full answer to your question, but the error you're getting suggests using `PhantomData`, which would at least get rid of your syntax problem. – Silvio Mayolo Jan 13 '19 at 03:45
  • You may find [When is it appropriate to use an associated type versus a generic type?](https://stackoverflow.com/q/32059370/3650362) to have some useful answers. – trent Jan 13 '19 at 12:16

1 Answers1

1

Just remove the trait bound from your struct.

struct Data<T> {
    mys: T
}

You can still add methods and trait implementations for Data<T> requiring more specific bounds on T, but you don’t need them to define the layout of Data<T>, so you shouldn’t specify them there (and in this case, you can’t, unless you add a PhantomData member referring to A).

Your code has a number of other errors, but I trust you’ll figure them out. Feel free to comment if you get stuck again.

Anders Kaseorg
  • 3,657
  • 22
  • 35
  • Thank you very much; this solved it. In addition to the pub/private errors, the other thing that needed to be changed was this: ```impl crate::general::MyTrait for crate::specific::MyS { fn val(self) -> crate::specific::Aval { self.val } }``` – Turtles Are Cute Jan 13 '19 at 03:59
  • The answer to my follow-on question of reducing verbosity: [Associated types](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types) – Turtles Are Cute Jan 13 '19 at 15:34