比较相等时如何帮助推断泛型向量的类型

时间:2015-05-17 01:39:30

标签: rust

我有以下代码:

struct HeadTail<T>(T, Vec<T>);

fn head_tail<T : Clone>(v: &Vec<T>) -> Option<HeadTail<T>> {
    match v.len() {
        0 => None,
        _ => {
            let mut tmp_v = v.clone();
            let head = tmp_v.remove(0);
            Some(HeadTail(head, tmp_v))
        }
    }
}

#[test]
fn head_tail_many() {
    let vec = vec![1, 2, 3, 4];
    let result = head_tail(&vec);

    match result {
        None => unreachable!(),
        Some(HeadTail(head, tail)) => {
            assert_eq!(1, head);
            assert_eq!(3, tail.len());
            assert_eq!([2, 3, 4], tail);
        }
    };
}

Online demo with the problem

它失败并出现以下异常:

<std macros>:5:8: 5:33 error: the trait `core::cmp::PartialEq<collections::vec::Vec<_>>` is not implemented for the type `[_; 3]` [E0277]
<std macros>:5 if ! ( * left_val == * right_val ) {

为什么Rust在这种情况下不能推断出类型?

我该怎么做才能让它知道任何数字类型(例如u8)?

2 个答案:

答案 0 :(得分:5)

调试这些类型的东西时,create a MCVE很有用。这是一个例子:

fn main() {
    let vec = vec![1, 2, 3, 4];
    assert_eq!([1,2,3,4], vec);
}

错误

<std macros>:5:8: 5:33 error: the trait `core::cmp::PartialEq<collections::vec::Vec<_>>` is not implemented for the type `[_; 4]` [E0277]
<std macros>:5 if ! ( * left_val == * right_val ) {
                      ^~~~~~~~~~~~~~~~~~~~~~~~~

所以,PartialEq出现了某种错误,让我们尝试进一步减少:

fn main() {
    let vec = vec![1, 2, 3, 4];
    [1,2,3,4] == vec;
}

有相同的基本错误:

<anon>:3:5: 3:21 error: the trait `core::cmp::PartialEq<collections::vec::Vec<_>>` is not implemented for the type `[_; 4]` [E0277]
<anon>:3     [1,2,3,4] == vec;
             ^~~~~~~~~~~~~~~~

_中的Vec<_>表示尚未破坏的类型。让我们使用显式类型来查看是否存在问题:

fn main() {
    let vec = vec![1u8, 2, 3, 4];
    [1u8,2,3,4] == vec;
}

不,仍然是同样的错误:

<anon>:3:5: 3:23 error: the trait `core::cmp::PartialEq<collections::vec::Vec<u8>>` is not implemented for the type `[u8; 4]` [E0277]
<anon>:3     [1u8,2,3,4] == vec;
             ^~~~~~~~~~~~~~~~~~

让我们尝试翻转一下:

fn main() {
    let vec = vec![1u8, 2, 3, 4];
    vec == [1u8,2,3,4];
}

嗯。这有效!在原始代码中交换订单也有效。

当然,剩下的大问题是为什么。我们来看看docs for Vec,特别是关于PartialEq的部分:

impl<'a, 'b, A, B> PartialEq<[B; 4]> for Vec<A>
    where A: PartialEq<B>
{
    fn eq(&self, other: &[B; 4]) -> bool { ... }
}

因此,如果您可以测试Vec<A>&[B; 4]是否相等,则可以测试AB的相等性。反过来呢? docs for arrays根本没有提到Vec(这是有道理的,因为它们更像是核心功能),并且没有PartialEq的任何逆实现。这当然看起来令人惊讶,我没有很好的解释为什么他们不在那里......

啊,这似乎发生在this commit。这是提交消息:

  

失去的主要实施是比较的能力   &[T]Vec<T>(按此顺序)。

     

此更改还会修改assert_eq!宏以免考虑   两个方面的平等,只有左/右的方向   形式到宏。由于这一事实,这种修改是有动机的   &[T] == Vec<T>不再编译,导致数百个错误   在标准库中的单元测试中(可能在整个标准库中)   社区也是如此)。

Manishearth found一个comprehensive blog post,详细描述了这一变化背后的基本原理!

答案 1 :(得分:2)

要扩展@ Shepmaster的答案,这里的问题是==运算符的实现在这种情况下是不对称的。我们有impl PartialEq<Vec<T>> for [T; n],但不是相反。也许我们应该有一个反向实现,但是通用数组类型还没有得到很好的支持。

这根本不是一个推理问题,这是一个比较两种不同类型和Rust没有对称实现的问题。