I am attempting to fully utilize Traits (or Abstraction?) in which all Structs do not use types, but instead use Traits for variables. In doing so, I am running into the "issue" that a Struct needs to "know" about a Trait that it doesn't see on its' own "level".
Example, in which there are 3 Structs: A, B, C. A is at the bottom of the layer. B has a variable of type ATrait. C has a variable of type BTrait. But, C has to know of A and I don't want that. Is there a way around that?
I don't want to have to do: let c: C<B<A>>... to create a new C. I would like C to only know about B, let c: C<B>..., or something like that.
That works (updated example in which I added in a Struct D with function calls all the way down to A and a Testing/Mocking example).
A bit disappointed I can't get away with let d: D<C> = ..., but, no matter how many layers down I have traits, I can just do: let d: D<C<_>> = ... or let d: D<_> = ... (and that is weird).
And testing/mocking is simple enough as well.
However, the different "new" functions I will have to implement, that will have to have the different Struct Types denoted within the signatures is going to be fun: fn new_something() -> Something<A<B<C<D<E<....>>>>, but I guess I understand that; I have to declare some concrete type somewhere.
It seems that you are confused about generics. What you are asking is simply not possible. When you use generic parameters, it's the caller's responsibility to provide the generic argument.
pub struct A {}
pub struct B<ATRAIT = A> { .. }
pub struct C<BTRAIT = B> { .. } // B here means B<A>
pub struct D<CTRAIT = C> { .. } // C here means C<B<A>>
pub fn new_d() -> D { .. } // D here means D<C<B<A>>>
some_fn would have to know how to construct SomeStructC, e.g.
Though at that point, given what code you have so far, you might as well just
#[derive(Default)]
pub struct D<CTRAIT = C> { .. }
let d_foo = D::<Foo>::default();
// Required for both this and the previous code block:
// `Foo` implements `Default` too
Here's a modification of your playground, perhaps it will be useful.
That said, I don't know exactly what your XY is, but this is seeming pretty non-idiomatic to me. So far you're doing everything by value, but if one extends the "traits not fields!" idea just a bit, you'll end up with all fields being manipulated via getters and setters only. That doesn't play well with Rust's borrowing design.[2] It's rare to use getters/setters in the same module/crate where the fields are visible even if not public.
Sort of long but if you read it all, it explains why you needed D<C<_>> without defaulted parameters in ascription position. ↩︎
I have updated my example to do a mixture of Defaults and Generic Traits, in which each Struct declares a Default type and states that the Default type must Implement a Trait.
In this way, each Struct is able to create its' own new function to create its local variable without having to know anything about the other Structs' variables; no D<C<B<A>>>.
Final 2 questions:
Is this "proper" code? As in, are there any drawbacks to this I need to be made aware of? Something along the lines of: "This is discouraged because..."
Did I use terminology correctly? "I created a Struct with a Default that must Implement a Trait". Just so I can re-use this knowledge with others correctly.