I am implementing a struct with a generic bounded to a trait, but that implementation is desirable to feature functions that bound the generic even more. Below is the example:
struct A<T> {
data: T
}
impl <T: AsRef<[u8]>> A<T> {
fn test(&self, t: &T) {}
fn more_bound<S: AsRef<[u8]> + PartialEq>(&self, t: &S) {
self.test(t);
}
}
I cannot really use a specialization as I don't implement a trait. Neither would I like to define a trait.
Are there any other options except changing the signature of test
to
fn test(&self, t: &impl AsRef<[u8]>) {}
?
Because such an approach seems to defeat the purpose of generics (in this case).
The compiler throws an error because in more_bound
you take an S
and then pass it into test
, which requires a T
. The fact that S
and T
are both AsRef<[u8]>
(and T
is weaker than S
) is irrelevant since those generics have to match a fixed, concrete type (you promised a &T
but gave an &S
- who knows what &S
is).
You can simply split the impl
into two parts:
impl<T: AsRef<[u8]>> A<T> {
fn test(&self, t: &T) {}
}
impl<T: AsRef<[u8]> + PartialEq> A<T> {
fn more_bound(&self, t: &T) {
self.test(t);
}
}
The second impl
will only be applicable for a T
that is AsRef<[u8]> + PartialEq
. As this bound guarantees that this T
is AsRef<[u8]>
, the more_bound
method can call test
, defined in the first impl
.
If your original goal was to allow more_bound
to be called with different types, you'll have to do the type-conversion via AsRef
yourself:
impl <T: AsRef<[u8]>> A<T> {
// Notice `test`takes the target of `AsRef<[u8]>`
fn test(&self, t: &[u8]) {}
fn more_bound<S: AsRef<[u8]> + PartialEq>(&self, t: &S) {
// `S` can be whatever we want, it never "meets" `T`.
self.test(t.as_ref());
}
}