Documentation of Peekable::next_if

The documentation for Peekable::next_if says:

...
// `next_if` saves the value of the next item if it was not equal to `expected`.
assert_eq!(iter.next(), Some(1));

I don't see how this is related. The next item is saved in Peekable's peeked field, but the iterator itself does not (should not?) advance when peeking. The next line with assert_eq(...) shows exactly that.

Is it just badly worded or am I missing something about next_if's actual behavior?


Another question I have is also about Peekable::next_if. It's match statement looks like this:

    match self.next() {
        Some(matched) if func(&matched) => Some(matched),
        other => {
            // Since we called `self.next()`, we consumed `self.peeked`.
            assert!(self.peeked.is_none());
            self.peeked = Some(other);
            None
        }
    }

What is the other match arm? What matches against other and what even is other? My google-fu didn't help, so I'm a little bit lost.

Thank you.

It's just pointing out that, because this is peekable, next_if doesn't advance the peekable iterator as a whole. (The inner iterator may be advanced if you haven't peeked it beforehand.) I'm afraid I'm not sure which part of the wording you find confusing.

The pattern in the second arm is just a variable name, so it will match anything. It's analogous to let other = [some value]. So in this case, other is either None or Some(did_not_match). And so self.peeked is set to Some(Some(did_not_match)) or Some(None). Then None is returned.

2 Likes

I just don't see how this is related to the following assert_eq(..) that demonstrates that the iterator was not advanced.

It's the first time I see this pattern. I haven't seen it in the rust book or in rust-by-example or in the reference. Do you happen to have a link to some more documentation about this?

Edit: The inner iterator may be advanced if you haven't peeked it beforehand:

Oh, now I see what you mean. The iterator can do whatever it wants on next... :slight_smile:
I was learning string parsing today and had only &strs in my head :sweat_smile:

It's described here in the book and here in the reference

You know, that's a really good point. I skimmed all the usual references on match and the examples with a catch-all always use the non-binding _. So I don't have a reference for that in particular, but for a real short version, you can think of it as "a catch-all like _ but it assigns the value to the variable name".

However, it's useful to realize that the patterns in a match can also be used in a lot of other places. In particular for this discussion, let is based around patterns too:

let x = Some(1);
let Some(y) = x; // Like in a match, this works
assert_eq!(y, 1);
let _ = y; // you can do this too

So having just a variable on the left side of an arm in a match statement is like assigning that variable. Here's the section of the book that covers patterns generally, which can hopefully give you a better feel overall.

1 Like

This won't work because let requires an irrefutable pattern, e.g. a pattern that always matches. Here the None pattern is not covered, so the match could fail.

This is the one sentence I missed.

One way to ensure you’ve covered every possibility is to have a catchall pattern for the last arm: for example, a variable name matching any value can never fail and thus covers every remaining case.


Thanks. I see it now. Looks like I was too negligent while reading the book, i.e. to dumb to read properly.