我想做这样的事情:
let count = self.line_current[self.line_current_pos..]
.split(self.separator)
.take(i_count)
.map(|s|if s.is_empty() { Ok(()) } else { Err(s) })
.count()?;
if count != i_count {
Err("Unexpected newline")
} else {
Ok(())
}
这是针对面向行的解析函数,它跳过预期数量的分隔符。
然而,迭代器上的count()函数使用迭代器,并且不能与std :: ops :: Try一起使用。是否有一种优雅的方式来计算有效项目,但如果其中一项与标准不符,则会立即返回错误?
答案 0 :(得分:0)
假设您要解析"field1,field2,A,B,C"
形式的字符串 - 所以在开头有一些垃圾字段要跳过(在这种情况下为2),但是您也希望有3个令牌它 - 如果存在少于3个字段,你想要输出错误。
这种功能的签名如下:
fn parse(line: &str, skip: usize, count: usize) -> Result<Vec<Token>, Error>
在这种情况下,我们会拨打parse("field1,field2,A,B,C", 2, 3)
。
所以我们首先将字符串拆分为','
:
line.split(',')
我们跳过skip
字段:
.skip(skip)
我们尝试解析每个字段
.map(str::parse)
现在优雅的技巧 - 将一个元素附加到迭代器的末尾,如果我们到达它将导致错误。我们将Iterator::chain
与Some(T)
- Some(T)
函数一起使用,就像本例中一个元素的迭代器一样。
.chain(Some(Err(Error::NotEnoughTokens)))
采取我们需要的许多元素
.take(count)
将整个事情收集到Result<Vec<Token>, Error>
中 - 这才有效!返回的错误将是第一次遇到,因此首先解析错误,然后是NotEnoughTokens
错误。
.collect()
使用它的完整代码,包括令牌解析样板,如下所示:
use std::str::FromStr;
#[derive(Debug)]
enum Token {
A,
B,
C,
}
#[derive(Debug)]
enum Error {
NotEnoughTokens,
InvalidToken,
}
impl FromStr for Token {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
match s {
"A" => Ok(Token::A),
"B" => Ok(Token::B),
"C" => Ok(Token::C),
_ => Err(Error::InvalidToken),
}
}
}
fn parse(line: &str, skip: usize, count: usize) -> Result<Vec<Token>, Error> {
line.split(',')
.skip(skip)
.map(str::parse)
.chain(Some(Err(Error::NotEnoughTokens)))
.take(count)
.collect()
}
fn main() {
println!("{:?}", parse("A,B,C", 0, 2)); // Ok([A, B])
println!("{:?}", parse("A,B,C", 0, 3)); // Ok([A, B, C])
println!("{:?}", parse("A,B,C", 0, 4)); // Err(NotEnoughTokens)
println!("{:?}", parse("A,B,C,D", 0, 4)); // Err(InvalidToken)
println!("{:?}", parse("field1,B,C", 1, 2)); // Ok([B, C])
println!("{:?}", parse("field1,field2,C", 2, 1)); // Ok([C])
println!("{:?}", parse("field1,B,C", 2, 2)); // Err(NotEnoughTokens)
println!("{:?}", parse("f1,f2,f3,A", 3, 1)); // Ok([A])
}