Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

while loops that advance an iterator – is this good practise?

I am writing a top-down parser in rust from scratch, this is what i have so far.

use std::str::Chars;

struct Lexer<'a> {
    peek: Option<char>,
    chars: Chars<'a>,
}

impl<'a> Lexer<'a> {
    fn new(string: &'a str) -> Self {
        let mut chars = string.chars();
        Self {
            peek: chars.next(),
            chars
        }
    }

    fn next(&mut self) -> Option<char> {
        let peek = self.peek;
        self.peek = self.chars.next();
        peek
    }

    fn peek(&self) -> Option<char> {
        self.peek
    }

    fn next_if<F>(&mut self, cond: F) -> Option<char> where
        F: FnOnce(char) -> bool {
    
        if cond(self.peek()?) {
            self.next()
        } else {
            None
        }
    }

    fn eat_while<F>(&mut self, cond: F) where
        F: FnOnce(char) -> bool {

        while self.next_if(cond).is_some() {}
    }
}

here you can see my eat_while implementation takes in a lambda (called cond) and advances the iterator until the specified value doesn’t match cond, or the chars iterator is empty.
because the while loop advances the iterator, there is no need for a loop body. however, i am told an empty while loop is bad practise

what i tried instead is recreating the "next_if" functionality in eat_while.
however, this appears to be impossible:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

while cond(self.peek()).is_some()
// does not work

because self.peek() returns an option, there is no way to pass it into cond.
i tried unwrapping self.peek():

while cond(self.peek().unwrap()).is_some()
// does not work

this will panic if you reach the end of the file, so it is DEFINITELY not an option.

>Solution :

You can use Option::and_then in that case:

while self.peek().and_then(|p| cond(p)).is_some() {/*...*/}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading