为什么对显式类型向量进行索引会失败并出现类型推断错误?

5
在下面的 代码 中,我创建了一个向量,然后将其用作闭包的内容:
fn main() {
    let f = {
        let xs: Vec<(usize, usize)> = Vec::new();
        // populate xs
        move |i, j| xs[j].1 - xs[i].0
    };
    let x = f(1usize, 2usize);
}

为什么虽然向量明确指定了类型,但代码仍无法通过类型推断而编译失败?
error[E0282]: type annotations needed
 --> src/main.rs:5:21
  |
5 |         move |i, j| xs[j].1 - xs[i].0
  |                     ^^^^^ cannot infer type
  |
  = note: type must be known at this point
1个回答

5
在Rust中,[i]语法来自于实现了std::ops::Index trait这个特性。
该特性的实现如下:
pub trait Index<Idx> 
where
    Idx: ?Sized, 
{
    type Output: ?Sized;
    fn index(&self, index: Idx) -> &Self::Output;
}

您可以多次为类型实现Index,每次使用不同的类型作为Idx参数。通过使用对Index的全面实现,Vec支持尽可能多的不同索引机制:

impl<T, I> Index<I> for Vec<T>
where
    I: SliceIndex<[T]>, 

这适用于任何也实现了SliceIndex的类型,包括像您尝试使用的usize类型,还有像范围类型,比如Range<usize>(例如0..5)和RangeFrom<usize>(例如0..)。在闭包内部,编译器不知道会使用哪个Index的实现方式,并且每种可能性都可能有不同的Output类型,这就是为什么它无法推断出单个类型的原因。
您可以通过注释闭包的参数来解决这个问题:
let f = {
    let xs: Vec<(usize, usize)> = Vec::new();
    //
    move |i: usize, j: usize| xs[j].1 - xs[i].0
};
let x = f(1, 2);

谢谢,但我明确地将1和2输入为1usize2usize,以便它知道要使用哪个实现。但它仍然不起作用。我必须显式地输入参数。为什么会这样? - Listerone
@Listerone。因为f是泛型的,所以需要适用于任何可能的索引类型。在f内部声明实际类型为usize会有效地使其不再是泛型。在f外部声明类型只是选择该调用的类型 - 但是f仍然需要适用于所有其他类型。 - Peter Hall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接