Reputation: 255145
I have the following code:
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);
}
};
}
And it fails with the following exception:
<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 ) {
Why can Rust not infer the type in this case?
What can I do to let it know it's any numeric type (eg u8
)?
Upvotes: 3
Views: 565
Reputation: 432139
It's useful to create a MCVE when debugging these types of things. Here's an example:
fn main() {
let vec = vec![1, 2, 3, 4];
assert_eq!([1,2,3,4], vec);
}
With the error
<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 ) {
^~~~~~~~~~~~~~~~~~~~~~~~~
So, there's some kind of error with PartialEq
, let's try to reduce further:
fn main() {
let vec = vec![1, 2, 3, 4];
[1,2,3,4] == vec;
}
With the same basic error:
<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;
^~~~~~~~~~~~~~~~
The _
in Vec<_>
means an as-yet-undermined type. Let's use explicit types to see if that's the problem:
fn main() {
let vec = vec![1u8, 2, 3, 4];
[1u8,2,3,4] == vec;
}
Nope, still the same error:
<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;
^~~~~~~~~~~~~~~~~~
Let's try flipping things around:
fn main() {
let vec = vec![1u8, 2, 3, 4];
vec == [1u8,2,3,4];
}
Hmm. This works! Swapping the order in your original code also works.
Of course, the big question left is why. Let's look at the docs for Vec
, specifically the section about PartialEq
:
impl<'a, 'b, A, B> PartialEq<[B; 4]> for Vec<A>
where A: PartialEq<B>
{
fn eq(&self, other: &[B; 4]) -> bool { ... }
}
So, you can test a Vec<A>
to an &[B; 4]
for equality, if you can test A
and B
for equality. What about the other way around? The docs for arrays don't mention Vec
at all (which makes sense, as they are more of a core feature), and there aren't any inverse implementations of PartialEq
. This certainly seems surprising, and I have no good explanation for why they aren't there...
Ah, it appears this happened in this commit. Here's the commit message:
The primary implementation which was lost was the ability to compare
&[T]
andVec<T>
(in that order).This change also modifies the
assert_eq!
macro to not consider both directions of equality, only the one given in the left/right forms to the macro. This modification is motivated due to the fact that&[T] == Vec<T>
no longer compiles, causing hundreds of errors in unit tests in the standard library (and likely throughout the community as well).
Manishearth found a comprehensive blog post that describes the rationale behind this change in good detail!
Upvotes: 5
Reputation: 16198
To expand on @Shepmaster's answer, the issue here is that the implementation for the ==
operator is asymmetric in this case. We have an impl PartialEq<Vec<T>> for [T; n]
, but not the reverse. Perhaps we should have a reverse implementation, but generic array types aren't well supported yet.
This wasn't an issue with inference at all, it was an issue of comparing two different types and Rust not having a symmetric implementation.
Upvotes: 2