切片和iter()同时

Abh*_*yal 7 rust

我试图弄清楚为什么这不起作用(游乐场):

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);
}
Run Code Online (Sandbox Code Playgroud)

错误:

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`
Run Code Online (Sandbox Code Playgroud)

但这确实有效:

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);
}
Run Code Online (Sandbox Code Playgroud)

请解释一下Rust中的矢量如何工作以及上面的差异iter().

Luk*_*odt 15

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

&b[1..b.len()].iter()
Run Code Online (Sandbox Code Playgroud)

等于:

&(b[1..b.len()].iter())
Run Code Online (Sandbox Code Playgroud)

并且由于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}>`
Run Code Online (Sandbox Code Playgroud)

哇,这真是一口气.但是我们可以看到违反了函数的zip()某些特征约束要求.那么,让我们来看看所述函数的签名:

fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> 
    where U: IntoIterator
Run Code Online (Sandbox Code Playgroud)

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

&b[1..b.len()].iter()
Run Code Online (Sandbox Code Playgroud)

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

&(b[1..b.len()].iter())
Run Code Online (Sandbox Code Playgroud)
  1. 一种表达方式foo[bar]令人厌恶*::std::ops::Index::index(&foo, bar).这是这里最复杂的部分,但在文档中查看这一点可以发现表达式b[1..b.len()]具有类型[i32].

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

  3. 现在&:你借这个Iter<_, _>东西,结果&Iter<_, _>.

嘿,这匹配错误信息!看看最后一点:

note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&std::slice::Iter<'_, {integer}>`
Run Code Online (Sandbox Code Playgroud)

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

但我们可以做得更好!IntoIterator也实现了&[T],所以你也可以删除它.iter(),它的工作原理!

工作守则

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

注意:我也删除了范围的上限以使它们半开,正如Paolo Falabella建议的那样.


Pao*_*lla 5

您的第一个版本存在运算符优先级问题:首先&a[1..a.len()].iter()应用iter()然后引用它,以对a的引用结束std::slice::Iter.

正如你可以在看文档的Iter,有一个impl Iterator对Iter,但不是&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);
}
Run Code Online (Sandbox Code Playgroud)