如何在不消耗迭代器 int rust 的情况下获取元素(在 rust 中重写 strtol 的问题)
how to get element without consuming iterator int rust(problem with rewriting strtol in rust)
我在 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,
}
},
None => break,
}
}
result
}
问题是在运行strtol
之后,迭代器指向数字后的第二个字符,它应该指向数字后的第一个字符。
例如,如果输入“1234abc”,在调用 strtol
之后,迭代器指向 b
应该是 a
.
您的代码失败是因为您查看 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
}
你不能,真的,因为那不是 Iterator
的工作方式。
你可能需要一个 Peekable
,它可以让你 peek()
迭代器而不消耗该项目,但我认为仅此而已:AFAIK 而 Rust 有 DoubleEndedIterator
让你从后面迭代,它没有 双向 迭代器(让你向后移动/调整迭代器),至少我不知道。
虽然我也不确定你为什么要输入 Chars
,但为什么不呢,例如拿一个 &str
并让 strtol
return 提取数字的元组和“其余”作为切片?这看起来更像 Rust。
顺便说一下,您的 loop
可以通过使用 while let
:
来简化
while let Some(c) = chars.next()
match c.to_digit(10) {
Some(i) => result = result * 10 + i64::from(i),
None => break,
}
}
我在 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,
}
},
None => break,
}
}
result
}
问题是在运行strtol
之后,迭代器指向数字后的第二个字符,它应该指向数字后的第一个字符。
例如,如果输入“1234abc”,在调用 strtol
之后,迭代器指向 b
应该是 a
.
您的代码失败是因为您查看 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
}
你不能,真的,因为那不是 Iterator
的工作方式。
你可能需要一个 Peekable
,它可以让你 peek()
迭代器而不消耗该项目,但我认为仅此而已:AFAIK 而 Rust 有 DoubleEndedIterator
让你从后面迭代,它没有 双向 迭代器(让你向后移动/调整迭代器),至少我不知道。
虽然我也不确定你为什么要输入 Chars
,但为什么不呢,例如拿一个 &str
并让 strtol
return 提取数字的元组和“其余”作为切片?这看起来更像 Rust。
顺便说一下,您的 loop
可以通过使用 while let
:
while let Some(c) = chars.next()
match c.to_digit(10) {
Some(i) => result = result * 10 + i64::from(i),
None => break,
}
}