链接不同类型的迭代器

时间:2015-11-06 18:25:01

标签: iterator rust

链接不同类型的迭代器时会出现类型错误。

let s = Some(10);
let v = (1..5).chain(s.iter())
        .collect::<Vec<_>>();

输出:

<anon>:23:20: 23:35 error: type mismatch resolving `<core::option::Iter<'_, _> as core::iter::IntoIterator>::Item == _`:
 expected &-ptr,
    found integral variable [E0271]
<anon>:23     let v = (1..5).chain(s.iter())
                             ^~~~~~~~~~~~~~~
<anon>:23:20: 23:35 help: see the detailed explanation for E0271
<anon>:24:14: 24:33 error: no method named `collect` found for type `core::iter::Chain<core::ops::Range<_>, core::option::Iter<'_, _>>` in the current scope
<anon>:24             .collect::<Vec<_>>();
                       ^~~~~~~~~~~~~~~~~~~
<anon>:24:14: 24:33 note: the method `collect` exists but the following trait bounds were not satisfied: `core::iter::Chain<core::ops::Range<_>, core::option::Iter<'_, _>> : core::iter::Iterator`
error: aborting due to 2 previous errors

但是在压缩时它可以正常工作:

let s = Some(10);
let v = (1..5).zip(s.iter())
        .collect::<Vec<_>>();

输出:

[(1, 10)]

为什么Rust能够推断出zip的正确类型而不是chain的正确类型,我该如何解决?注:我希望能够为任何迭代器执行此操作,因此我不想要一个适用于Range和Option的解决方案。

1 个答案:

答案 0 :(得分:10)

首先,请注意迭代器会产生不同的类型。我在数字中添加了一个明确的u8,以使类型更明显:

fn main() {
    let s = Some(10u8);
    let r = (1..5u8);

    let () = s.iter().next(); // Option<&u8>
    let () = r.next();        // Option<u8>
}

当你chain两个迭代器时,两个迭代器必须产生相同的类型。这是有道理的,因为迭代器无法“切换”当它到达一个结束并从第二个结束时它输出的类型:

fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter> 
    where U: IntoIterator<Item=Self::Item>
//                        ^~~~~~~~~~~~~~~ This means the types must match

为什么zip有效?因为它没有这个限制:

fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> 
    where U: IntoIterator
//                       ^~~~ Nothing here!

这是因为zip返回一个元组,每个迭代器都有一个值;一种新类型,与源迭代器的类型不同。一个迭代器可以是整数类型,另一个可以为所有zip关注返回自己的自定义类型。

  

为什么Rust能够推断出zip的正确类型,而不是chain

这里没有类型推断;那是另一回事。这只是普通的类型不匹配。

  

我该如何解决?

在这种情况下,你的内部迭代器产生一个对整数Clone - 能力类型的引用,所以你可以使用cloned创建一个新的迭代器来克隆每个值,然后两个迭代器都会具有相同的类型:

fn main() {
    let s = Some(10);
    let v: Vec<_> = (1..5).chain(s.iter().cloned()).collect();
}

如果您已完成该选项,您还可以使用使用迭代器into_iter

fn main() {
    let s = Some(10);
    let v: Vec<_> = (1..5).chain(s.into_iter()).collect();
}