比较相等性时如何帮助推断通用向量的类型
How to help infer the type for generic vector when comparing equality
我有以下代码:
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);
}
};
}
失败并出现以下异常:
<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
)?
调试这些类型的东西时,它对 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 { ... }
}
因此,如果可以测试 A
和 B
是否相等,则可以测试 Vec<A>
到 &[B; 4]
是否相等。反过来呢? docs for arrays 根本没有提到 Vec
(这是有道理的,因为它们更像是一个核心功能),并且没有 PartialEq
的任何反向实现。这看起来确实令人惊讶,而且我无法很好地解释为什么它们不存在...
啊,看来这发生在 this commit。这是提交消息:
The primary implementation which was lost was the ability to compare
&[T]
and Vec<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).
a comprehensive blog post 详细描述了此更改背后的基本原理!
为了扩展@Shepmaster 的回答,这里的问题是 ==
运算符的实现在这种情况下是不对称的。我们有一个 impl PartialEq<Vec<T>> for [T; n]
,但不是相反。也许我们应该有一个反向实现,但是通用数组类型还没有得到很好的支持。
这根本不是推理的问题,这是比较两种不同类型和 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);
}
};
}
失败并出现以下异常:
<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
)?
调试这些类型的东西时,它对 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 { ... }
}
因此,如果可以测试 A
和 B
是否相等,则可以测试 Vec<A>
到 &[B; 4]
是否相等。反过来呢? docs for arrays 根本没有提到 Vec
(这是有道理的,因为它们更像是一个核心功能),并且没有 PartialEq
的任何反向实现。这看起来确实令人惊讶,而且我无法很好地解释为什么它们不存在...
啊,看来这发生在 this commit。这是提交消息:
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).
为了扩展@Shepmaster 的回答,这里的问题是 ==
运算符的实现在这种情况下是不对称的。我们有一个 impl PartialEq<Vec<T>> for [T; n]
,但不是相反。也许我们应该有一个反向实现,但是通用数组类型还没有得到很好的支持。
这根本不是推理的问题,这是比较两种不同类型和 Rust 没有对称实现的问题。