rust代码,为什么将两个RangeInclusive进行Zip以后无法调用rev?

// RangeInclusive编译不通过
fn main() {
    for k in (1..=10).zip(1..=20).rev() {
        println!("{} {}", k.0, k.1);
    }
}

提示:

error[E0277]: the trait bound RangeInclusive<i32>: ExactSizeIterator is not satisfied

改成Range就正常:

// Range编译通过
fn main() {
    for k in (1..11).zip(1..21).rev() {
        println!("{} {}", k.0, k.1);
    }
}

但是更奇怪的是,如果我不进行zip操作,那么无论是RangeInclusive还是Range都能编译通过。

造成这样的差异(ExactSizeIterator is not satisfied)的原因是什么?

阅读 2k
2 个回答

rev 需要参数是 DoubleEndedIterator 。

而 zip 的结果 Zip<A,B> ,需要 A, B 均是 ExactSizeIterator 才会实现 DoubleEndedIterator: Zip<A,B>。因为只有两个 iterator 的长度都已知,才能确定 zip 后 iterator 的终点。

但是,RangeInclusive 只对 i8, u8, i16, u16 实现了 ExactSizeIterator 。原因是,ExactSizeIterator 有一个成员叫 len() ,返回长度。而对 u32 以上,其值会超过 usize::MAX ,无法实现。source。所以 RangeInclusive<i32> 在 zip 过之后,结果没有实现 DoubleEndedIterator ,就不能调用 rev 了。

由于 rev 本身不需要 ExactSizeIterator ,只需要 DoubleEndedIterator 就可以调用,而 RangeInclusive 实现了 DoubleEndedIterator ,所以 RangedInclusive 自己是可以调用 rev 的。

fefe的回答已经完全解释清楚,但感觉内容逻辑调整一下更好理解:

在此重新调整一下顺序并按条列出:

  1. rev 本身不需要 ExactSizeIterator ,只需要 DoubleEndedIterator 就可以调用
  2. RangeInclusive 实现了 DoubleEndedIterator
  3. RangeInclusive 只对 i8, u8, i16, u16 实现了 ExactSizeIterator (因为更大的类型无法实现len方法,可能会溢出usize::MAX)
  4. zip 的结果 Zip<A,B> A, B 均是 ExactSizeIterator 才会实现 DoubleEndedIterator: Zip<A,B>,因为只有两个 iterator 的长度都已知,才能确定 zip 后 iterator 的终点。
  5. 因为没有满足均是 ExactSizeIterator,zip后没有实现DoubleEndedIterator,因而无法调用rev
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进