Rust - 多次调用迭代器方法



我有以下 rust 代码:

fn tokenize(line: &str) -> Vec<&str> {
let mut tokens = Vec::new();
let mut chars = line.char_indices();
for (i, c) in chars {
match c {
'"' => {
if let Some(pos) = chars.position(|(_, x)| x == '"') {
tokens.push(&line[i..=i+pos]);
} else {
// Not a complete string
}
}
// Other options...
}
}
tokens
}

我试图优雅地从行中提取一个用双引号括起来的字符串,但由于chars.position采用可变引用并且chars被移动到 for 循环中,我得到一个编译错误 - "移动后借用的值"。编译器建议在 for 循环中借用chars,但这不起作用,因为不可变引用不是迭代器(可变引用会导致原始问题,我无法再次借用position(。

我觉得应该有一个简单的解决方案。 有没有惯用的方法可以做到这一点,或者我需要回归到一个接一个地附加字符?

因为for循环将获得chars的所有权(因为它调用.into_iter()(,所以你可以使用while循环手动遍历chars

fn tokenize(line: &str) -> Vec<&str> {
let mut tokens = Vec::new();
let mut chars = line.char_indices();
while let Some((i, c)) = chars.next() {
match c {
'"' => {
if let Some(pos) = chars.position(|(_, x)| x == '"') {
tokens.push(&line[i..=i+pos]);
} else {
// Not a complete string
}
}
// Other options...
}
}
}

如果你只是对for循环进行脱糖,它就可以工作:

fn tokenize(line: &str) -> Vec<&str> {
let mut tokens = Vec::new();
let mut chars = line.char_indices();
while let Some((i, c)) = chars.next() {
match c {
'"' => {
if let Some(pos) = chars.position(|(_, x)| x == '"') {
tokens.push(&line[i..=i+pos]);
} else {
// Not a complete string
}
},
_ => {},
}
}
tokens
}

正常的 for 循环可防止对迭代器进行额外的修改,因为这通常会导致令人惊讶且难以阅读的代码。将其作为while循环进行没有这样的保护。

如果您只想找到带引号的字符串,那么我在这里根本不会使用迭代器。

fn tokenize(line: &str) -> Vec<&str> {
let mut tokens = Vec::new();
let mut line = line;
while let Some(pos) = line.find('"') {
line = &line[(pos+1)..];
if let Some(end) = line.find('"') {
tokens.push(&line[..end]);
line = &line[(end+1)..];
} else {
// Not a complete string
}
}
tokens
}

最新更新