rustiteratorstrtol

how to get element without consuming iterator int rust(problem with rewriting strtol in rust)


I implement strtol in Rust like this:

fn strtol(chars: &mut Chars<'_>) -> i64 {
    let mut result: i64 = 0;
    loop {
        match chars.next() {
            Some(c) => {
                match c.to_digit(10) {
                    Some(i) => result = result * 10 + i64::from(i),
                    None => break,
                }
            },
            None => break,
        }
    }
    result
}

the problem is that after runing strtol, the iterator point to the second character after number digit, which should point at the first character after number digit. For example, if input "1234abc", after calling strtol, iterator point to b which should be a.


Solution

  • Your code fails because you look at chars.next to see if it's a valid digit or not then stops if it isn't. This means that the first non-digit will be consumed, as you observed. To fix this, you can pass in a Peekable:

    use std::iter::Peekable;
    
    fn strtol<I: Iterator<Item = char>>(chars: &mut Peekable<I>) -> i64 {
        let mut result: i64 = 0;
        loop {
            // first peek the element here
            match chars.peek() {
                Some(c) => match c.to_digit(10) {
                    Some(i) => result = result * 10 + i64::from(i),
                    None => break,
                },
                None => break,
            }
            // at this point we know it's a digit so we consume it
            chars.next();
        }
        result
    }
    
    fn main() {
        let test = "1234abcd";
        let mut iter = test.chars().peekable();
        println!("{}", strtol(&mut iter)); // 1234
        println!("{}", iter.collect::<String>()); // abcd
    }
    

    Playground link