为什么用推断的Item类型调用Iter上的cloned()允许它传递给这个函数?

时间:2015-06-19 16:38:18

标签: iterator rust

我试图了解Iterator及其工作原理,我希望你们中的一些人可以向我解释这段代码:

fn main() {
    let a: Vec<_> = (0..10).map(|_| 2).collect();
    let it = a.iter();
    print(it);
}

fn print<I: Iterator<Item=usize>>(iter: I) {
    for x in iter {
        println!("{}",x);
    }
}

我知道上面的代码非常复杂,但它是我从更复杂的版本创建的简单代码,它更有意义,只是为了找到问题的核心并更好地理解它。

在rustc中编译此代码时,我遇到了这个编译错误:

src/main.rs:5:5: 5:8 error: type mismatch resolving `<core::slice::Iter<'_, _> as core::iter::Iterator>::Item == usize`:
 expected &-ptr,
    found usize [E0271]
src/main.rs:5     print(it);
                  ^~~

我通过改变let来修复它:

let it = a.iter().cloned();

let it = a.iter().map(|&x| x);

据我所知,错误表明编译器无法安全地推断出我试图传递的Item的类型作为参数,但为什么调用cloned()或map会改变什么?

1 个答案:

答案 0 :(得分:2)

您的print函数需要usize的迭代器作为参数,但it(在您的第一个版本中)是一个产生&usize值的迭代器,即引用到usize

cloned()实际上将Clone::clone映射到迭代器上,因此它将&T的迭代器转换为T的迭代器,以便修复程序中的类型不匹配。

您的最终版本(let it = a.iter().map(|&x| x);)也将迭代器从&T的迭代器转换为T的迭代器,但这次是通过使用模式匹配解除引用元素。

由于print实际上不需要拥有迭代器的元素,因此您还可以通过将其类型更改为以下内容来解决问题:

fn print<'a, I: Iterator<Item=&'a usize>>(iter: I)