首页 > 解决方案 > 为迭代器创建 peek_while

问题描述

我正在尝试peek_while为我的迭代器创建一个方法,它基本上应该做相同的事情,take_while但只在谓词匹配后使用字符。我从 https://stackoverflow.com/a/30540952/10315665和实际take_while源代码https://github.com/rust-lang/rust/blob/2c7bc5e33c25e29058cbafefe680da8d5e9220e9/library/core/src/中获得了一些灵感iter/adapters/take_while.rs#L42-L54并得出以下结果:

pub struct PeekWhile<I: Iterator, P> {
    iter: Peekable<I>,
    predicate: P,
}

impl<I, P> fmt::Debug for PeekWhile<I, P>
where
    I: Iterator + Debug,
    <I as Iterator>::Item: Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("PeekWhile")
            .field("iter", &self.iter)
            .finish()
    }
}

impl<I, P> Iterator for PeekWhile<I, P>
where
    I: Iterator,
    P: FnMut(&I::Item) -> bool,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        let n = self.iter.peek()?;
      
        while let Some(n) = self.iter.peek() {
            if (self.predicate)(&n) {
                return self.iter.next();
            } else {
                break;
            }
        }
        None
    }
}

pub trait PeekWhileExt: Iterator {
    fn peek_while<P>(self, predicate: P) -> PeekWhile<Self, P>
    where
        Self: Iterator,
        Self: Sized,
        P: FnMut(&Self::Item) -> bool,
    {
        PeekWhile {
            iter: self.peekable(),
            predicate,
        }
    }
}

impl<I: Iterator> PeekWhileExt for I {}

这导致了无限循环,虽然我不确定为什么,但我看到该take_while::next方法没有循环,所以我将其更改为:

let n = self.iter.peek()?;

if (self.predicate)(n) {
    Some(n)
} else {
    None
}

现在给了我:

mismatched types
expected associated type `<I as Iterator>::Item`
         found reference `&<I as Iterator>::Item`

那么我将如何创建这样一个迭代器呢?到目前为止的代码是否正确,以及如何完成它?我知道 itertools 有https://docs.rs/itertools/0.10.1/itertools/trait.Itertools.html#method.peeking_take_while这听起来很有希望,但这是一个学习项目,无论是在编程概念还是 rust 本身(我'正在创建一个 JSON 解析器顺便说一句),所以我非常有兴趣在没有任何库的情况下完成那部分代码。

示例用例(未测试):

let chars = "keyword:".chars();

assert_eq!(chars.peek_while(|c| c.is_alphabetic()).collect::<String>(), "keyword");
assert_eq!(chars.next().unwrap(), ':');
//                                 ^
// Very important that the next char doesn't get lost

感谢任何帮助!

标签: rust

解决方案


推荐阅读