【问题标题】:Implementing PartialEq for a struct with From types为具有 From 类型的结构实现 PartialEq
【发布时间】:2016-09-25 08:16:54
【问题描述】:

我正在尝试在我创建的结构和我的结构实现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

【问题讨论】:

    标签: struct rust traits


    【解决方案1】:

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

    我们想对编译器说的话:

    Data 应该在 any 生命周期内实现 From&lt;&amp;'a T&gt; '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

    【讨论】:

    • 也谢谢你。我接受了 Dogbert 的回答,因为它是最快的,但非常感谢您提供指向 nomicon 的链接。
    【解决方案2】:

    您只需稍加修改即可使PartialEq 工作:需要Data: From&lt;&amp;'a T&gt;,因为您使用的是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 子句中的for
    • @Shu:for 是用来引入生命周期名称的,语义上意味着无论'a 的值如何,以下关系都应该是有效的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    • 1970-01-01
    • 2015-10-08
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    相关资源
    最近更新 更多