Reputation: 883
I want to use Rust's Enumerate
to get both a character and its index in the slice from each iteration:
fn main() {
for (j, val) in "dummy string".chars().enumerate().rev() {
// ...
}
}
When I compile with cargo run
I get:
error: the trait `core::iter::ExactSizeIterator` is not implemented for the type `core::str::Chars<'_>` [E0277]
for (j, val) in "dummy string".chars().enumerate().rev() {
^~~
help: see the detailed explanation for E0277
error: the trait `core::iter::ExactSizeIterator` is not implemented for the type `core::str::Chars<'_>` [E0277]
for (j, val) in "dummy string".chars().enumerate().rev() {
// ...
}
I can understand why this would fail: the rev
method needs an ExactSizeIterator
since it needs to know the last element in the slice and its index from the beginning. Is it possible to get an ExactSizeIterator
in this case, or does the length of the iterator need to be baked in at compile time? If it is possible, is it just a matter of specifying the iterator with something like as ExactSizeIterator
or something like that?
Upvotes: 0
Views: 1717
Reputation: 431679
The docs for ExactSizeIterator
state:
An iterator that knows its exact length.
Many
Iterator
s don't know how many times they will iterate, but some do. If an iterator knows how many times it can iterate, providing access to that information can be useful. For example, if you want to iterate backwards, a good start is to know where the end is.
But that's not the actual trait required by rev
!
fn rev(self) -> Rev<Self>
where Self: DoubleEndedIterator
The ExactSizeIterator
requirement comes from Enumerate
's implementation of DoubleEndedIterator
:
impl<I> DoubleEndedIterator for Enumerate<I>
where I: ExactSizeIterator + DoubleEndedIterator
Is it possible to get an
ExactSizeIterator
in this case, or does the length of the iterator need to be baked in at compile time?
The Chars
iterator needs to support both ExactSizeIterator
and DoubleEndedIterator
, but it only natively supports DoubleEndedIterator
.
In order to implement ExactSizeIterator
for Chars
, you'd need to be able to look at an arbitrary string and know (in a small enough time) how many characters it is made of. This is not generally possible with the UTF-8 encoding, the only encoding of Rust strings.
The length of the iterator is never a compile-time constant.
is it just a matter of specifying the iterator with something like
as ExactSizeIterator
You cannot make a type into something it is not.
If you really need this, you could collect it all into a big Vec
:
fn main() {
let chars: Vec<_> = "dummy string".chars().collect();
for (j, val) in chars.into_iter().enumerate().rev() {
println!("{}, {}", j, val)
}
}
It's also possible you actually want the characters in reverse order with the count in increasing direction:
fn main() {
for (j, val) in "dummy string".chars().rev().enumerate() {
println!("{}, {}", j, val)
}
}
But you said this:
a character and its index in the slice
Since strings are UTF-8, it's possible you mean you want the number of bytes into the slice. That can be found with the char_indices
iterator:
fn main() {
for (j, val) in "dummy string".char_indices().rev() {
println!("{}, {}", j, val)
}
}
Upvotes: 6