为什么' rev().rev() '工作,但' rev().skip(1).rev() '不工作? &

  • 本文关键字:rev 工作 skip 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>());
}
// This compiles
fn main() {
let s = "Hello!";
println!("{}", &s.chars().rev().rev().collect::<String>());
}
// This *does not* compile
fn main() {
let s = "Hello!";
println!("{}", &s.chars().rev().skip(1).rev().collect::<String>());
}

最后一个不编译:

error[E0277]: the trait bound `Chars<'_>: ExactSizeIterator` is not satisfied
--> src/main.rs:3:45
|
3 |     println!("{}", &s.chars().rev().skip(1).rev().collect::<String>());
|                                             ^^^ the trait `ExactSizeIterator` is not implemented for `Chars<'_>`
|
= note: required because of the requirements on the impl of `ExactSizeIterator` for `Rev<Chars<'_>>`
= note: required because of the requirements on the impl of `DoubleEndedIterator` for `Skip<Rev<Chars<'_>>>`
error[E0599]: the method `collect` exists for struct `Rev<Skip<Rev<Chars<'_>>>>`, but its trait bounds were not satisfied
--> src/main.rs:3:51
|
3  |        println!("{}", &s.chars().rev().skip(1).rev().collect::<String>());
|                                                      ^^^^^^^ method cannot be called on `Rev<Skip<Rev<Chars<'_>>>>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Skip<Rev<Chars<'_>>>: DoubleEndedIterator`
which is required by `Rev<Skip<Rev<Chars<'_>>>>: Iterator`
`Rev<Skip<Rev<Chars<'_>>>>: Iterator`
which is required by `&mut Rev<Skip<Rev<Chars<'_>>>>: Iterator`

<一口>操场

有人能解释一下为什么会这样吗?

调用.chars()返回实现DoubleEndedIteratorIterator(Chars),而使用.rev()则需要。

fn rev(self) -> Rev<Self>
where
Self: DoubleEndedIterator
然后调用.skip()产生一个新的Iterator(Skip),其中只有如果Iterator(本例中为Chars)同时实现DoubleEndedIteratorExactSizeIterator,则实现DoubleEndedIterator
impl<I> DoubleEndedIterator for Skip<I>
where
I: DoubleEndedIterator + ExactSizeIterator

但是,Chars没有实现ExactSizeIterator。所以DoubleEndedIterator没有为Skip实现。所以现在调用.rev()的要求不再适用于第二次调用。

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

例如,my_str.chars()得到一个Chars结构体,它是一个迭代器。呼叫.rev()转到Rev<Chars>

.rev()要求IDoubleEndedIterator(这是有意义的,反转只需从后到前迭代即可完成)。

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

可在任何迭代器上调用(这是有意义的)。

然而如果I实现了DoubleEndedIteratorExactSizeIterator,则Skip<I>只实现了DoubleEndedIterator

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

在我们看你写的东西之前,最后一点: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.

两个rev()无论如何是一个noop,Iterator是懒惰的,所以第二个rev()取消了第一个,除非迭代器在两个调用之间被消耗。

要跳过迭代器的最后一项,然后按顺序收集,我将这样做:

use std::iter::{DoubleEndedIterator, FromIterator, Iterator};
fn collect_rev_nth_n_rev<I, C>(items: I, n: usize) -> C
where
I: DoubleEndedIterator,
C: FromIterator<<I as Iterator>::Item>,
{
let mut iter = items.rev();
iter.nth(n);
iter.rev().collect()
}
fn main() {
let result: String = collect_rev_nth_n_rev("Hello!".chars(), 0);
assert_eq!("Hello", result);
}

nth()通常是很好的优化。

相关内容

  • 没有找到相关文章

最新更新