为什么 `rev().rev()` 有效,但 `rev().skip(1).rev()` 无效?

HKT*_*Lee 11 rust

正如标题所示,在 Rust 中,.rev().rev()有效, .rev().skip(1)有效,但.rev().skip(1).rev()无效。下面是演示:

// This compiles
fn main() {
    let s = "Hello!";
    println!("{}", &s.chars().rev().skip(1).collect::<String>());
}
Run Code Online (Sandbox Code Playgroud)
// This compiles
fn main() {
    let s = "Hello!";
    println!("{}", &s.chars().rev().rev().collect::<String>());
}
Run Code Online (Sandbox Code Playgroud)
// This *does not* compile
fn main() {
    let s = "Hello!";
    println!("{}", &s.chars().rev().skip(1).rev().collect::<String>());
}
Run Code Online (Sandbox Code Playgroud)

最后一个无法编译:

// This compiles
fn main() {
    let s = "Hello!";
    println!("{}", &s.chars().rev().skip(1).collect::<String>());
}
Run Code Online (Sandbox Code Playgroud)

操场

有人可以解释为什么会出现这种情况吗?

Val*_*tin 19

调用.chars()返回一个Iterator( Chars) ,该 ( ) 实现了DoubleEndedIterator,而 using 则.rev()需要。

fn rev(self) -> Rev<Self>
where
    Self: DoubleEndedIterator
Run Code Online (Sandbox Code Playgroud)

然后调用.skip()会产生一个 new Iterator( Skip) ,只有DoubleEndedIteratorIterator(在本例中Chars)同时实现DoubleEndedIterator和 时,它才会实现ExactSizeIterator

impl<I> DoubleEndedIterator for Skip<I>
where
    I: DoubleEndedIterator + ExactSizeIterator
Run Code Online (Sandbox Code Playgroud)

然而,Chars并没有实施ExactSizeIterator。所以DoubleEndedIterator没有实现Skip. .rev()所以现在第二次调用不再满足调用的要求。


Opt*_*ach 7

rev方法返回一个名为的结构Rev<I>,其中I是您调用它的迭代器。

例如,my_str.chars()获取一个Chars作为迭代器的结构。打电话.rev()给你Rev<Chars>

.rev()要求I是 a DoubleEndedIterator(这是有道理的,反转是通过从后到前迭代来完成的)。

skip方法返回一个名为的结构Skip<I>,其中类似地,I是您调用它的任何迭代器。

这可以在任何迭代器上调用(这是有道理的)。

然而Skip<I>DoubleEndedIteratorI实现DoubleEndedIterator ExactSizeIterator时才实现。

这意味着,我们只能.rev调用Skip<I>if I: DoubleEndedIterator + ExactSizeIterator

在我们查看您所写的内容之前,最后一点:Chars实现DoubleEndedIterator 但不是 ExactSizeIterator,因为字符在以 utf8 编码时是可变长度的。

看看整个事情:

s
    .chars() // DoubleEndedIterator
    .rev()   // DoubleEndedIterator
    .skip()  // Doesn't implement DoubleEndedIterator because it doesn't implement ExactSizeIterator
    .rev()   // Err, we need DoubleEndedIterator here.
Run Code Online (Sandbox Code Playgroud)