如何在不消耗迭代器 int rust 的情况下获取元素在 rust 中重写 strtol 的问题

问题描述

我像这样在 Rust 中实现了 strtol

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,}
            },}
    }
    result
}

问题是运行strtol后,迭代器指向数位后的第二个字符,应该指向数位后的第一个字符。 例如输入“1234abc”,调用strtol后,迭代器指向b,应该是a

解决方法

你不能,真的,因为这不是 Iterator 的工作方式。

您可能需要一个 Peekable,它可以让您 peek() 迭代器而不消耗该项目,但我认为仅此而已:AFAIK 而 Rust 具有 DoubleEndedIterator 可以让您从在后面,它没有双向迭代器(它可以让你向后移动/调整迭代器),至少我不知道。

虽然我不确定您为什么要输入 Chars,但为什么不例如取一个 &str 并让 strtol 返回提取数字的元组,并将“其余部分”作为切片返回?这看起来更像 Rust-ish。

顺便说一下,您的 loop 可以通过使用 while let 来简化:


while let Some(c) = chars.next()
    match c.to_digit(10) {
        Some(i) => result = result * 10 + i64::from(i),None => break,}
}
,

您的代码失败,因为您查看 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),},}
        // 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