有计数的最佳方法() - &gt;在interator上结果<usize>函数?

时间:2017-09-09 03:09:47

标签: rust

我想做这样的事情:

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一起使用。是否有一种优雅的方式来计算有效项目,但如果其中一项与标准不符,则会立即返回错误?

1 个答案:

答案 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::chainSome(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])
}