为具有 From 类型的结构实现 PartialEq

Implementing PartialEq for a struct with From types

我正在尝试在我创建的结构和我的结构实现 From 特性的其他类型之间实现 PartialEq。实际代码更复杂,并为其他类型实现 From,但这是核心问题的简化版本。

我希望能够做到:

let s = Data::from(5);
assert_eq!(5, s);

这是基本代码:

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 T: Into<Data>
{
    fn eq(&self, other: &T) -> bool {
        let o = Data::from(other);
        self.data == o.data
    }
}

但我得到一个错误:

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`

所以我将特征绑定更改为编译器建议的内容,并添加了所有请求的生命周期以修复 missing lifetime specifier 错误:

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
    }
}

我从中得到

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 {
   |>     ^

现在我迷路了,因为它建议完全按照我所做的去做,但它拒绝了……:/

Code on the playground

你只需要一个小小的修改就可以使 PartialEq 工作:需要 Data: From<&'a T> 因为你使用的是 Data::from(other) 而不是 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
    }
}

您还需要进行两个微小的修改才能使 assert_eq! 正常工作:

  1. 由于您正在为数据实现 PartialEq,RHS 是 T,LHS 是 Data,因此您只能使用 Data::from(5) == 5 进行比较,而不是5 == Data::from(5).

  2. 如果要使用assert_eq!,则需要实现Debug

最终工作代码:

#[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);
}

编译器是正确的:添加 where Data: From<&T> 正确的做法。但是正如您已经注意到的,在这种情况下需要一个生命周期说明符。但是我们如何声明它?

我们想对编译器说的话:

Data should implement From<&'a T> for any lifetime 'a

我们不能impl块上声明生命周期,因为这表达了不同的东西。我们需要使用 “higher-ranked lifetime bounds”,如下所示:

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

这解决了您的主要问题。


还有两个无关紧要的附加问题:

  • 您需要交换 assert_eq!() 中的参数,因为 PartialEq 的使用方式:assert_eq!(s, 5)
  • 你需要 #[derive(Debug)] 你的 Data 类型

您可以找到 工作版本 here on the playground