PartialEq implementation for structure with types From

I am trying to implement PartialEq between the structure I created and other types for which my structure implements the From property. The actual code is more complex and implements From for other types, but this is a stripped-down version of the main 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 attempt:

 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 associated with 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 he offers to do what I did, and he refused ...: /

Playground Code

+5
source share
2 answers

You only need a little modification to make this work PartialEq : require Data: From<&'a T> , since you are 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 assert_eq! work assert_eq! :

  • Since you are implementing PartialEq for data, RHS is T and LHS is Data , so you can only compare using Data::from(5) == 5 , 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); } 
+4
source

The compiler is right: adding where Data: From<&T> is the right thing. But, as you already noticed, in this case a life cycle specifier is required. But how to declare it?

What we want to say to the compiler:

Data must implement From<&'a T> for any life 'a

We cannot declare a lifetime in an impl block because it expresses something else. Instead, we need to use "earlier time estimates," as shown below:

  where Data: for<'a> From<&'a T> // ^^^^^^^ 

This fixes your underlying problem.


There are two minor, unrelated additional issues:

  • you need to swap the arguments in assert_eq!() , due to the use of the PartialEq method: assert_eq!(s, 5)
  • you need #[derive(Debug)] for your Data type

Here you can find the working version on the playground .

+7
source

All Articles