问题描述
我像这样在 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
}