As title, in Rust, .rev().rev()
works, .rev().skip(1)
works, but .rev().skip(1).rev()
does not. The following is the demonstration:
// 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>());
}
The last one does not compile:
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`
Playground
Could someone explain why this is the case?
collect() can take all the values in an Iterator 's stream and stick them into a Vec . And the map method is now generating Result<i32, &str> values, so everything lines up.
You can make your iterator peekable and peek the first item; if it's None , then the iterator is empty.
An iterator is responsible for the logic of iterating over each item and determining when the sequence has finished. When you use iterators, you don't have to reimplement that logic yourself. In Rust, iterators are lazy, meaning they have no effect until you call methods that consume the iterator to use it up.
Both way is OK ! I used to use Rev 1 for the original version of the document. But recently I moved to a new company where (they) we use Rev 00. Firstly I was surprised but later on I had different perspective: the newest edition has no revision at all, so Rev 0 sounds more logical. Version 1.0, 2.0, 3.0... Revision 00, 1.0, 2.0...
My experience is the Original Document is Rev 1 and any changes to it would then become Rev 2. Is there a right way, or only what our system says? Both way is OK ! I used to use Rev 1 for the original version of the document. But recently I moved to a new company where (they) we use Rev 00.
We use Rev A as Original or Initial Release. They used to be IR but some thought it was Initial Release some thought In Revision. We adopted the same level structure as our Engineering drawings. Something people were already familiar with. Unless a customer or Regulatory Body requires it to be different.
Over 100,000 customers use Rev from industries like legal, media, education, and more, meaning there are always a variety of files available to work on. Rev provides a free online editor that makes it easy to listen to the file and type at the same time. As a freelancer, you’re your own boss and control your own schedule.
Calling .chars()
returns an Iterator
(Chars
) which implements DoubleEndedIterator
, which using .rev()
requires.
fn rev(self) -> Rev<Self>
where
Self: DoubleEndedIterator
Then calling .skip()
produces a new Iterator
(Skip
), which only implements DoubleEndedIterator
if the Iterator
(in this case Chars
) implements both DoubleEndedIterator
and ExactSizeIterator
.
impl<I> DoubleEndedIterator for Skip<I>
where
I: DoubleEndedIterator + ExactSizeIterator
However, Chars
does not implement ExactSizeIterator
. So DoubleEndedIterator
is not implemented for Skip
. So now the requirement for calling .rev()
is no longer uphold for the second call.
The rev
method returns a structure called Rev<I>
where I
is whatever iterator you called it on.
For example,
my_str.chars()
gets you aChars
struct which is an iterator. Calling.rev()
gets youRev<Chars>
.
.rev()
requires that I
be a DoubleEndedIterator
(which makes sense, reversing is done by just iterating from the back to the front).
The skip
method returns a structure called Skip<I>
where similarly, I
is whatever iterator you called it on.
This is callable on any iterator (which makes sense).
However, Skip<I>
only implements DoubleEndedIterator
if I
implements DoubleEndedIterator
and ExactSizeIterator
.
That means, that we can only call .rev
on a Skip<I>
if I: DoubleEndedIterator + ExactSizeIterator
.
One last piece before we look at what you've written: Chars
implements DoubleEndedIterator
but not ExactSizeIterator
since characters are variable length when encoded in utf8.
Taking a look at this whole thing:
s
.chars() // DoubleEndedIterator
.rev() // DoubleEndedIterator
.skip() // Doesn't implement DoubleEndedIterator because it doesn't implement ExactSizeIterator
.rev() // Err, we need DoubleEndedIterator here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With