I am trying to implement PartialEq
between a struct I created and other types for which my struct implements the From
trait. The real code is more complex and implements From
for other types, but this is a stripped down version of the core problem.
I want to be able to do:
let s = Data::from(5);
assert_eq!(5, s);
This is the base code:
struct Data {
data: i64,
}
impl From<i64> for Data {
fn from(v: i64) -> Data {
Data { data: v }
}
}
impl<'a> From<&'a i64> for Data {
fn from(v: &'a i64) -> Data {
Data { data: v.clone() }
}
}
This was my first try:
impl<T> PartialEq<T> for Data
where T: Into<Data>
{
fn eq(&self, other: &T) -> bool {
let o = Data::from(other);
self.data == o.data
}
}
but I get an error:
error: the trait bound `Data: std::convert::From<&T>` is not satisfied [--explain E0277]
--> <anon>:21:17
|>
21 |> let o = Data::from(other);
|> ^^^^^^^^^^
help: consider adding a `where Data: std::convert::From<&T>` bound
note: required by `std::convert::From::from`
So I changed the trait bound to what the compiler suggested and added all the requested lifetimes to fix the missing lifetime specifier
error:
impl<'a, T> PartialEq<T> for Data
where T: 'a, Data: From<&'a T>
{
fn eq(&self, other: &'a T) -> bool {
let o = Data::from(other);
self.data == o.data
}
}
From which I get
error: method not compatible with trait [--explain E0308]
--> <anon>:31:5
|>
31 |> fn eq(&self, other: &'a T) -> bool {
|> ^ lifetime mismatch
note: expected type `fn(&Data, &T) -> bool`
note: found type `fn(&Data, &'a T) -> bool`
note: the anonymous lifetime #2 defined on the block at 31:39...
--> <anon>:31:40
|>
31 |> fn eq(&self, other: &'a T) -> bool {
|> ^
note: ...does not necessarily outlive the lifetime 'a as defined on the block at 31:39
--> <anon>:31:40
|>
31 |> fn eq(&self, other: &'a T) -> bool {
|> ^
help: consider using an explicit lifetime parameter as shown: fn eq(&self, other: &'a T) -> bool
--> <anon>:31:5
|>
31 |> fn eq(&self, other: &'a T) -> bool {
|> ^
And now I'm lost, as it suggests to do exactly what I did and it refused... :/
Code on the playground
The compiler is right: adding where Data: From<&T>
is the right thing to do. But as you already noticed, a lifetime specifier is required in this case. But how do we declare it?
What we want to say to the compiler:
Data
should implementFrom<&'a T>
for any lifetime'a
We can't declare the lifetime on the impl
block, because this expresses something different. We instead need to use “higher-ranked lifetime bounds”, as shown here:
where Data: for<'a> From<&'a T>
// ^^^^^^^
This fixes your main problem.
There are two minor, unrelated, additional problems:
assert_eq!()
, because of the way PartialEq
is used: assert_eq!(s, 5)
#[derive(Debug)]
for your Data
typeYou can find a working version here on the playground.
You just need one tiny modification to make that PartialEq
work: require Data: From<&'a T>
since you're using Data::from(other)
and not other.into()
:
impl<T> PartialEq<T> for Data
where for<'a> Data: From<&'a T>
{
fn eq(&self, other: &T) -> bool {
let o = Data::from(other);
self.data == o.data
}
}
You also need two tiny modifications to make the assert_eq!
work:
Since you're implementing PartialEq for Data, the RHS is T
and the LHS is Data
, so you can only compare using Data::from(5) == 5
and not 5 == Data::from(5)
.
You need to implement Debug
if you want to use assert_eq!
.
Final working code:
#[derive(Debug)]
struct Data {
data: i64,
}
impl From<i64> for Data {
fn from(v: i64) -> Data {
Data { data: v }
}
}
impl<'a> From<&'a i64> for Data {
fn from(v: &'a i64) -> Data {
Data { data: v.clone() }
}
}
impl<T> PartialEq<T> for Data
where for<'a> Data: From<&'a T>
{
fn eq(&self, other: &T) -> bool {
let o = Data::from(other);
self.data == o.data
}
}
fn main() {
let s = Data::from(5);
assert_eq!(s, 5);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With