как получить элемент без использования итератора int rust (проблема с перезаписью strtol в rust)

Я реализую strtol в Rust так:

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
}

проблема в том, что после запуска strtol итератор указывает на второй символ после цифры номера, который должен указывать на первый символ после цифры номера. Например, при вводе 1234abc после вызова strtol итератор указывает на b, который должен быть a.


person Jack Zhang    schedule 04.02.2021    source источник


Ответы (2)


Ваш код не работает, потому что вы смотрите на chars.next, чтобы убедиться, что это правильная цифра или нет, а затем останавливается, если это не так. Это означает, что, как вы заметили, будет использована первая не цифра. Чтобы исправить это, вы можете передать 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
}

Ссылка на игровую площадку

person Aplet123    schedule 04.02.2021
comment
Peekable это именно то, что я хочу. Большое спасибо! - person Jack Zhang; 04.02.2021

На самом деле вы не можете, потому что Iterator так не работает.

Вам может потребоваться Peekable, который позволит вам peek() итератор, не потребляя элемент, но я думаю об этом: AFAIK, в то время как в Rust есть DoubleEndedIterator, который позволяет выполнять итерацию сзади, у него нет двунаправленных итераторов (которые позволяют перемещать / настраивать итератор назад ), по крайней мере, я не знаю.

Хотя я тоже не уверен, почему вы вводите Chars, почему бы, например, взять &str и заставить strtol вернуть кортеж извлеченного числа, а остальное - как срез? Это кажется более ржавым.

Кстати, ваш loop можно упростить, используя while let:


while let Some(c) = chars.next()
    match c.to_digit(10) {
        Some(i) => result = result * 10 + i64::from(i),
        None => break,
    }
}
person Masklinn    schedule 04.02.2021
comment
Peekable может решить мою проблему. Большое спасибо. Также спасибо за «while let». почему бы и нет, например взять & str и заставить strtol вернуть кортеж извлеченного числа, а остальное - как срез? Slice - это хорошо, но я хочу реализовать функцию на основе указателя. просто личные предпочтения. - person Jack Zhang; 04.02.2021