首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >片和iter()同时

片和iter()同时
EN

Stack Overflow用户
提问于 2016-12-09 13:03:10
回答 3查看 3.2K关注 0票数 7

我试图找出为什么这不起作用(游乐场):

代码语言:javascript
复制
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);
}

错误:

代码语言:javascript
复制
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`

但这确实有效:

代码语言:javascript
复制
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);
}

请解释向量在锈蚀中是如何工作的,以及当我iter()时,上面的区别。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-12-09 13:41:00

简单地说,:您可能误解了操作符优先级:

代码语言:javascript
复制
&b[1..b.len()].iter()

等于:

代码语言:javascript
复制
&(b[1..b.len()].iter())

由于zip()期望实现IntoIterator,所以调用失败,因为对迭代器类型的引用不会实现上述特性。

充分解释

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

代码语言:javascript
复制
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}>`

哇,这可真够多的。但是我们可以看到,zip()的某些特性约束要求被违反了。那么,让我们看一下上述函数的签名:

代码语言:javascript
复制
fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> 
    where U: IntoIterator

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

代码语言:javascript
复制
&b[1..b.len()].iter()

要彻底地分析这个问题,我们需要了解一些东西,但我会试着把它分解。首先,让我们通过插入更多括号来消除操作符优先级的歧义。上面的代码片段相当于:

代码语言:javascript
复制
&(b[1..b.len()].iter())
  1. 表达式foo[bar] desugares为*::std::ops::Index::index(&foo, bar)。这是这里最复杂的部分,但是在文档中查找这个部分会发现表达式b[1..b.len()]具有[i32]类型。
  2. 在该类型上,调用iter(),它返回一个类型Iter<_, _>,它是片的迭代器类型。
  3. 现在,&:你借用Iter<_, _>的东西,导致了&Iter<_, _>

这符合错误信息!看最后一个音符:

代码语言:javascript
复制
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(),这样就可以工作了!

工作守则

代码语言:javascript
复制
let s: i32 = a[1..].iter()
    .zip(&b[1..])
    .map(|(x, y)| x * y)
    .sum();

注意:我还删除了范围的上限,使其半开,如保罗·法拉贝拉所言

票数 15
EN

Stack Overflow用户

发布于 2016-12-09 13:45:03

您的第一个版本有一个操作符优先的问题:&a[1..a.len()].iter()首先应用iter(),然后引用它,最后引用一个std::slice::Iter

正如您在Iter上看到的那样,有一个用于Iterimpl Iterator,但没有针对&Iter的。这就是第一个错误想要说的:(看看上面写着:&std::slice::Iter<'_, {integer}>不是迭代器的部分)。

简化一下,您可以拥有:

代码语言:javascript
复制
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);
}
票数 5
EN

Stack Overflow用户

发布于 2016-12-09 13:38:26

Iterator::zip需要一些实现IntoIterator的东西。

不是传递Iterator,而是传递对Iterator的引用。Iterator会发生变异,而引用是不够的。

您可以使用括号来解决这一问题,以明确您试图从

代码语言:javascript
复制
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);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41061165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档