rust - 使用 peekable 时出现意外的迭代器行为
问题描述
use std::str::Chars;
trait Extractor {
fn peek_first(&mut self) -> Option<char>;
}
impl <'a> Extractor for Chars<'a> {
fn peek_first(&mut self) -> Option<char> {
let mut pk = self.peekable();
pk.peek().and_then(|c| Some(*c))
}
}
#[cfg(test)]
mod tests {
use std::str::Chars;
use super::Extractor;
#[test]
fn peek_first_test() {
let mut iterator: Chars;
iterator = "".chars();
assert_eq!(iterator.peek_first(), None);
assert_eq!(iterator.as_str(), "".to_string());
iterator = "A".chars();
assert_eq!(iterator.peek_first(), Some('A'));
assert_eq!(iterator.as_str(), "A".to_string());
iterator = "AB".chars();
assert_eq!(iterator.peek_first(), Some('A'));
assert_eq!(iterator.as_str(), "AB".to_string());
}
}
我正在尝试特征并想在 Chars 迭代器上放置一个 peek_first() 。正如你所看到的,我使用 peekable 从 self 迭代器中获取一个 peekable 迭代器。我做了一个测试,看看 peek_first() 是否不会改变自迭代器状态,但它确实改变了。peeked for 元素改变了底层迭代器并推进它。
考试
assert_eq!(iterator.as_str(), "A".to_string());
失败,因为 iterator.as_str() 评估为空字符串。
这是正确的行为吗?我在任何有关 rust 的文档中都找不到这个。
解决方案
Iterator::peekable()
明确记录此行为的文档:
请注意,底层迭代器
peek
在第一次调用时仍然处于高级状态:为了检索下一个元素,next
在底层迭代器上调用,因此该方法的任何副作用(即,除了获取下一个值之外的任何副作用)next
都会发生.
由于Peekable
适用于任意迭代器,它只能使用标准迭代器接口来查看下一个元素,而从泛型中获取下一个元素的唯一方法Iterator
是调用next
它。
我想为您的代码中发生的事情添加更多上下文。该结构Peekable
是一个迭代器适配器。如果你有一个迭代器iter
,你可以调用iter.peekable()
来获取一个支持查看下一个元素的新迭代器。该方法按值peekable()
获取self
,这意味着它使用原始迭代器。所以使用它的标准方法是这样的代码:
let mut iter = "abc".chars().peekable();
Nowiter
是一个 peekable 迭代器,并且 peeking 不会自行推进iter
,而只是底层迭代器,它被包裹在其中Peekable
,不再可以直接访问。
但是,在您的代码中,每次调用时都会创建一个新的Peekable
包装器。peek_first()
包装器在peek_first()
. 在您的测试函数中,您只能看到底层迭代器,它每次都是高级的,如文档中所述。
peekable()
那么,如果按值获取并使用它,为什么甚至可以保留对底层迭代器的访问self
呢?这是因为对迭代器的可变引用的特征的转发实现Iterator
:
impl<'_, I> Iterator for &'_ mut I
where
I: Iterator + ?Sized;
该peek_first()
方法self
通过可变引用接收,因此它不能使用底层迭代器。相反,它使用转发实现对迭代器的可变引用,并且只使用可变引用。
作为旁注,您可以使用.and_then(|c| Some(*c))
将 anOption<&T>
转换为Option<T>
. 有一个专门的方法,称为cloned()
.
推荐阅读
- ios - 如何在 Swift 中删除领域中的对象
- ruby-on-rails - 为什么“唯一性:真实”验证在我的测试(Rails)中不起作用?
- amazon-web-services - 错误:InvalidProfileError - 尽管有配置文件,但无法找到配置文件(默认)
- javascript - Uncaught Invariant Violation:最小化 React 错误
- python - 用 json.dump 引发 JSONDecodeError("Extra data", s, end)
- docker - 将 env var 从 docker run cmd 在 jenkinsfile 中传递给 dockerfie
- jquery - 如果找到数据则显示警报 - JQUERY
- monitoring - 在 Glowroot 中无法看到我的 Vertx 应用程序的任何 Web 事务
- python - 如何为一种热编码实现生成器功能
- reactjs - React 中的 componentWillReceiveProps 问题