Slice and iter() simultaneously

时间:2016-12-09 13:03:11

标签: rust

I am trying to figure out why this does not work (Playground):

fn main() {
    let a = vec![1, 2, 3, 4];
    let b = a.clone();
    // slice and iter (wrong way)
    let s: i32 = &a[1..a.len()].iter()
        .zip(&b[1..b.len()].iter())
        .map(|(x, y)| x * y)
        .sum();
    println!("{}", s);
}

Error:

rustc 1.13.0 (2c6933acc 2016-11-07)
error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
 --> <anon>:6:10
  |
6 |         .zip(&b[1..b.len()].iter())
  |          ^^^ trait `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` not satisfied
  |
  = note: `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
  = note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`

error: no method named `map` found for type `std::iter::Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` in the current scope
 --> <anon>:7:10
  |
7 |         .map(|(x, y)| x * y)
  |          ^^^
  |
  = note: the method `map` exists but the following trait bounds were not satisfied: `&std::slice::Iter<'_, {integer}> : std::iter::Iterator`, `std::iter::Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>> : std::iter::Iterator`

But this does work:

fn main() {
    let a = vec![1, 2, 3, 4];
    let b = a.clone();
    // slice and iter (correct way)
    let s: i32 = a[1..a.len()].iter()
        .zip(b[1..b.len()].iter())
        .map(|(x, y)| x * y)
        .sum();
    println!("{}", s);
}

Please explain how vectors work in Rust and the difference above when I iter().

3 个答案:

答案 0 :(得分:15)

简而言之:您可能误解了运算符优先级:

&b[1..b.len()].iter()

等于:

&(b[1..b.len()].iter())

由于zip()期望实现IntoIterator的某些东西,所以调用失败,因为对此迭代器类型的引用没有实现所述特征。

完整解释

让我们试着理解错误信息!当然,我们首先看一下第一个错误:

error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
 --> <anon>:6:10
  |
6 |         .zip(&b[1..b.len()].iter())
  |          ^^^ trait `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` not satisfied
  |
  = note: `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
  = note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`
哇,这真是一口气。但是我们可以看到function zip()的某些特征限制要求被违反了。那么,让我们看看所述函数的签名:

fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> 
    where U: IntoIterator

重要的是other参数(类型U)。 U必须是IntoIterator。这个特性实现了很多类型......让我们检查一下我们尝试传递给zip()的类型:

&b[1..b.len()].iter()

要完全分析,我们需要了解一些东西,但我会尝试将其分解。首先,让我们通过插入更多括号来消除运算符优先级的歧义。上面的代码段相当于:

&(b[1..b.len()].iter())
  1. 表达式foo[bar]脱离*::std::ops::Index::index(&foo, bar)。这是最复杂的部分,但在文档中查看这一点可以发现表达式b[1..b.len()]的类型为[i32]

  2. 在该类型上,您调用iter(),它返回类型Iter<_, _>,它是切片的迭代器类型。

  3. 现在&:您借用Iter<_, _>这件事,导致&Iter<_, _>

  4. 嘿,这符合错误信息!看看最后一个注释:

    note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`
    

    那么......满足IntoIterator特质的是什么?例如,实现Iterator的每种类型(例如Iter<_, _>)也实现IntoIterator。所以你可以删除表达式中的&,它就可以了!

    但我们可以做得更好! IntoIterator也实施了&[T],因此您也可以删除.iter()并且有效!

    工作代码

    let s: i32 = a[1..].iter()
        .zip(&b[1..])
        .map(|(x, y)| x * y)
        .sum();
    

    注意:我还删除了范围的上限,使它们半开,as Paolo Falabella suggested

答案 1 :(得分:5)

您的第一个版本存在运算符优先级问题: -c, --close close connection on EOF from stdin 首先应用&a[1..a.len()].iter(),然后引用它,以对iter()的引用结束。

正如您在docs for Iter上看到的那样,std::slice::Iterimpl IteratorIter没有&Iter。 这是第一个错误试图说的:(查看说:&std::slice::Iter<'_, {integer}>不是迭代器的部分。)

简化一下,你可以:

fn main() {
    let a = vec![1, 2, 3, 4];
    // let b = a.clone(); // no more need to clone. We're going to only
                          // work with references

    let s: i32 = (&a[1..]).iter() // you don't need the a.len() 
                                  // to slice to the end
        .zip(&a[1..])             // &a implements IntoIter, which zip 
                                  // accepts, so you don't need iter() 
        .map(|(x, y)| x * y)
        .sum();
    println!("{}", s);
}

答案 2 :(得分:2)

Iterator::zip需要实现IntoIterator的内容。

您没有传递Iterator,而是将引用传递给IteratorIterator变异,参考不够。

您可以使用括号来明确说明您尝试从

中获取参考资料来解决此问题
fn main() {
    let a = vec![1, 2, 3, 4];
    let b = a.clone();

    let s: i32 = (&a)[1..a.len()].iter()
        .zip(((&b)[1..b.len()]).iter())
        .map(|(x, y)| x * y)
        .sum();

    println!("{}", s);
}