正如您所确定的,每个take_while
呼叫重复iter
, since take_while
takes self
和Peekable
字符迭代器是Copy http://doc.rust-lang.org/master/std/kinds/trait.Copy.html. (仅在 Rust 1.0 之前正确 - 编辑器)
您希望每次都修改迭代器,即take_while
操作于&mut
到你的迭代器。这正是.by_ref https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.by_ref适配器用于:
pub fn split(input: &str) -> Vec<String> {
let mut bits: Vec<String> = vec![];
let mut iter = input.chars().peekable();
loop {
match iter.peek().map(|c| *c) {
None => return bits,
Some(c) => if c.is_digit(10) {
bits.push(iter.by_ref().take_while(|c| c.is_digit(10)).collect());
} else {
bits.push(iter.by_ref().take_while(|c| !c.is_digit(10)).collect());
},
}
}
}
fn main() {
println!("{:?}", split("123abc456def"))
}
Prints
["123", "bc", "56", "ef"]
但是,我认为这是不正确的。
我实际上建议像平常一样写这个for
循环,使用char_indices https://doc.rust-lang.org/std/primitive.str.html#method.char_indices迭代器:
pub fn split(input: &str) -> Vec<String> {
let mut bits: Vec<String> = vec![];
if input.is_empty() {
return bits;
}
let mut is_digit = input.chars().next().unwrap().is_digit(10);
let mut start = 0;
for (i, c) in input.char_indices() {
let this_is_digit = c.is_digit(10);
if is_digit != this_is_digit {
bits.push(input[start..i].to_string());
is_digit = this_is_digit;
start = i;
}
}
bits.push(input[start..].to_string());
bits
}
这种形式还允许用更少的分配来做到这一点(即,String
s 不是必需的),因为每个返回值只是input
,我们可以用生命周期来说明这一点:
pub fn split<'a>(input: &'a str) -> Vec<&'a str> {
let mut bits = vec![];
if input.is_empty() {
return bits;
}
let mut is_digit = input.chars().next().unwrap().is_digit(10);
let mut start = 0;
for (i, c) in input.char_indices() {
let this_is_digit = c.is_digit(10);
if is_digit != this_is_digit {
bits.push(&input[start..i]);
is_digit = this_is_digit;
start = i;
}
}
bits.push(&input[start..]);
bits
}
所有改变的是类型签名,删除了Vec<String>
类型提示和.to_string
calls.
人们甚至可以编写这样的迭代器,以避免分配Vec
。就像是fn split<'a>(input: &'a str) -> Splits<'a> { /* construct a Splits */ }
where Splits
是一个实现的结构体Iterator<&'a str>
.