Yes, this is the pattern that I've been trying to find. Thanks @ogeon!
It seems that the way one leaves an associated type t
abstract is by forgetting about it altogether. In particular, one can introduce a new trait that omits the associated type t
entirely. Then, one can write a conversion that works universally. I use trait S
below for this purpose (@ogeon's suggestion above uses trait AnyT
for this purpose).
Here's that suggested pattern applied to my earlier example:
trait T : Debug { // The same as before
type t;
fn get (self:&Self) -> Self::t ;
fn doit (self:&Self, Self::t ) -> String ;
}
trait S : Debug { // S is implemented for all T below
fn doit (self:&Self) -> String ;
}
#[derive(Debug)]
struct Packed {
two : (Box<S>,Box<S>) // Use trait S here, not trait T
}
impl <A, B: T<t=A>> S for B { // Convert any T object into an S object
fn doit (self:&Self) -> String {
self.doit ( self.get () )
}
}
In sum, I've added trait S
, which is similar to T
except that associated type T::t
is absent.
This pattern is satisfying since it provides three useful views of associated type t
in trait T
:
-
The concrete view in
Foo
and inBar
, wheret
is known. -
The abstract view of
t
, e.g., within the implementation ofS
for any traitT
. In this case,t
is known, but it is abstract. -
The "forgetful" view provided by
S
, whereT::t
is absent, and thus any differences in typeT::t
are irrelevant. In this example, boxed versions ofFoo::Foo
andBar::Bar
can be given a common typeBox<S>
. Hence, they can be placed into data structures such as arrays and lists, etc.
This makes sense now. Thanks again!