Reputation: 667
I'm trying to write this in Rust:
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
struct Bar<F1: Foo, F2: Foo> {
f1: F1,
f2: F2,
}
impl<F1: Foo, F2: Foo> Bar<F1, F2> {
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
It refuses to compile, because F1::T
might be different from F2::T
, rendering the equality meaningless. I'd like to be able to resolve that by writing this:
impl<F1: Foo, F2: Foo> Bar<F1, F2>
where
F1::T = F2::T
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
But that tells me that equality constraints are not yet supported and refers me to this issue. Since it's been open since late 2014, I suspect it's not a feature that's arriving any time soon.
I can do this, and it'll compile:
struct Bar<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> {
f1: F1,
f2: F2,
}
impl<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> Bar<T, F1, F2>
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
But then I'm adding an additional generic parameter to the struct Bar
. If Foo
has multiple associated types that I want to constrain in this manner, then it'll get a bit messy.
My question is:
Bar
'more generic' with the addition of the additional type parameter T
?Edit:
I realize I simplified my example too much.
Suppose I actually have a Bar
that has an associated Baz
that has an associated Foo
that has an associated T
.
That's bit of a mouthful, so here is the example:
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
trait Baz {
type F: Foo;
fn get_inner_t(&self) -> <Self::F as Foo>::T;
}
struct Bar<B1: Baz, B2: Baz> {
b1: B1,
b2: B2,
}
impl<B1: Baz, B2: Baz> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
Of course it still doesn't compile because the T
s from get_inner_t
can differ. I do genuinely want to allow that the two Baz
s differ, and the Foo
s differ, but constrain their T
s to be the same.
I've tried to adapt the answer given, by writing
impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
But that gives this compile error:
Compiling type_bindings v0.1.0 (/home/harry/coding/rust_sandbox/type_bindings)
error: expected one of `(`, `,`, `::`, `<`, or `>`, found `=`
--> src/main.rs:18:38
|
18 | impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
| ^ expected one of `(`, `,`, `::`, `<`, or `>`
error: aborting due to previous error
error: could not compile `type_bindings`
To learn more, run the command again with --verbose.
If this multi-level extraction of associated types not permitted?
Upvotes: 1
Views: 1183
Reputation: 2182
While all @Aplet123 noted is valid, I think this is a syntactically neater way of writing it.
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
struct Bar<F1, F2>
where
F1: Foo,
F2: Foo<T = F1::T>,
{
f1: F1,
f2: F2,
}
impl<F1, F2> Bar<F1, F2>
where
F1: Foo,
F2: Foo<T = F1::T>,
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
trait Foo {
type T: PartialEq;
fn get_t(&self) -> Self::T;
}
trait Baz {
type F: Foo;
fn get_inner_t(&self) -> <Self::F as Foo>::T;
}
struct Bar<B1, B2>
where
B1: Baz,
B2: Baz<F = B1::F>,
{
b1: B1,
b2: B2,
}
impl<B1, B2> Bar<B1, B2>
where
B1: Baz,
B2: Baz<F = B1::F>,
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
Upvotes: 0
Reputation: 35482
You can "extract" the associated type:
struct Bar<F1: Foo, F2: Foo<T = <F1 as Foo>::T>> {
f1: F1,
f2: F2,
}
impl<F1: Foo, F2: Foo<T = <F1 as Foo>::T>> Bar<F1, F2>
{
fn test_eq(&self) -> bool {
self.f1.get_t() == self.f2.get_t()
}
}
For your edit, you can use some type aliases to clean up the syntax (not required but is nicer) then use impl
or add another generic to the impl (which doesn't make the struct more generic so it doesn't run into the same issues, however it does not let you put the bounds on the struct):
type GetT<T> = <T as Foo>::T;
type GetF<T> = <T as Baz>::F;
impl<B1: Baz, B2: Baz<F = impl Foo<T = GetT<GetF<B1>>>>> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
or
impl<T: PartialEq, B1: Baz<F = impl Foo<T = T>>, B2: Baz<F = impl Foo<T = T>>> Bar<B1, B2>
{
fn test_eq(&self) -> bool {
self.b1.get_inner_t() == self.b2.get_inner_t()
}
}
Upvotes: 5