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从自迭代器中获取peekable迭代器。我进行了测试,看peek_first()是否不会改变自我迭代器的状态,但是会改变。偷看元素更改了基础迭代器并进行了改进。
测试
assert_eq!(iterator.as_str(), "A".to_string());
由于iterator.as_str()计算为空字符串而失败。
这是正确的行为吗?在任何有关锈的文档中都找不到。
答案 0 :(得分:2)
Iterator::peekable()
的文档明确记录了此行为:
请注意,当第一次调用
peek
时,基础迭代器仍处于高级状态:为了检索下一个元素,在基础迭代器上调用next
,因此产生了任何副作用(即,除了获取next
方法的下一个值之外,其他任何事情都将发生。
由于Peekable
适用于任意迭代器,因此它只能使用标准迭代器接口来窥视下一个元素,并且从通用Iterator
获取下一个元素的唯一方法是调用{ {1}}。
我想在代码中添加更多内容。结构next
是迭代器适配器。如果您有一个迭代器Peekable
,则可以调用iter
获得一个 new 迭代器,该迭代器支持在下一个元素上进行窥视。方法iter.peekable()
按值取peekable()
,这意味着它消耗了原始的迭代器。因此,使用它的标准方式是这样的代码:
self
现在let mut iter = "abc".chars().peekable();
是一个可窥视的迭代器,并且窥视并不会使iter
本身前进,而只会使底层的迭代器前进,该迭代器包装在iter
中,而不是可以直接访问了。
但是,在您的代码中,每次调用Peekable
时,都会创建一个新的Peekable
包装器。包装器将放在peek_first()
的末尾。在测试函数中,您只会看到底层的迭代器,该迭代器每次都会高级,如文档中所述。
那么,如果peek_first()
取值peekable()
并使用它,为什么还能保留对底层迭代器的访问?这是由于the forwarding implementation of the Iterator
trait for mutable references to iterators:
self
impl<'_, I> Iterator for &'_ mut I
where
I: Iterator + ?Sized;
方法通过可变引用接收peek_first()
,因此它不能使用底层的迭代器。相反,它将转发实现用于对迭代器的可变引用,并且仅使用可变引用。
作为旁注,您可以使用self
将.and_then(|c| Some(*c))
变成Option<&T>
。有一个专用的方法,称为Option<T>
。