使用From类型为结构实现PartialEq

时间:2016-09-25 08:16:55

标签: struct rust traits

我正在尝试在我创建的struct和我的struct实现PartialEq trait的其他类型之间实现From。真正的代码更复杂,并为其他类型实现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

2 个答案:

答案 0 :(得分:7)

编译器是对的:添加where Data: From<&T> 是正确的事情。但正如您已经注意到的那样,在这种情况下需要使用生命周期说明符。但我们如何宣布

我们想对编译器说些什么:

  

Data应为{strong>任何生命周期From<&'a T>

实施'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

答案 1 :(得分:4)

您需要进行一项微小的修改才能使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 for Data,因此RHS为T且LHS为Data,因此您只能使用Data::from(5) == 5而不是{{1}进行比较}。

  2. 如果您想使用5 == Data::from(5),则需要实施Debug

  3. 最终工作代码:

    assert_eq!