Cloning a peekable chars iterator

Hey, I'm writing a lexer where I'm using Peekable<Chars<'a>> to iterate over the input string. At some point in the code I noticed that I need to be able to peek more than once. So I tried to clone the iterator and try to iterate over the clone and avoid consuming the original, but then I got an error I didn't understand.

let c = "".chars().peekable().cloned();

Gives the error

error[E0271]: type mismatch resolving `<std::iter::Peekable<std::str::Chars<'_>> as std::iter::Iterator>::Item == &_`
  --> <anon>:2:35
 2 |     let c = "".chars().peekable().cloned();
   |                                   ^^^^^^ expected char, found reference
   = note: expected type `char`
   = note:    found type `&_`

I read the error E0271 but it didn't help me understand the problem. Can someone explain?
PS: I know I can use itertools to be able to peek multiple times ahead, which would solve my issue.

1 Like

You probably want clone, not cloned :slight_smile: The former clones the iterator itself while the latter returns an adaptor that clones items.

Yeah, the error is hard to understand.

Instead of calling clone() you've called .cloned(), which changes what items are iterated. It's defined as:

fn cloned(self) … where Self: Iterator<Item=&T>

So it's for iterators that iterate references. The error message is trying to tell you that your iterator iterates char, not &char:

type mismatch resolving <yadayada as Iterator>::Item == &_

This says that for cloned() the Item of the Iterator is expected to be a reference & of something (anything) _. But for peekable chars iterator the item is char.

1 Like

You guys are right, thank you. I was looking at the page for the Iterator trait instead of Peekable, not wonder I didn't find .clone().

I do have a followup question:
When I clone a Peekable<Chars<'a>>, I'm not cloning the whole string the original iterator is referencing? I assume it's just getting another reference to the string that the Chars<'a> is holding.

Cloning of references is shallow, just clones the reference itself, so for iterators it should be very cheap (just clones an index into the string).

All right, thank you.