• Rust迭代器中的 by_ref 方法的用法
  • 发布于 2个月前
  • 195 热度
    0 评论
  • 耀国
  • 0 粉丝 31 篇博客
  •   
一旦在迭代器上附加了适配器,是否可以再次将适配器移除呢?通常来说,不可以!适配器会持有底层迭代器的所有权,并且不提供将其返还的方法。

迭代器的 by_ref 方法借用了迭代器的可变引用,这样一来,便可以将适配器应用于该引用。当消费完适配器中的项后,借用结束,并重新获得对原始迭代器的访问权限。

之前的文章中使用 take_while [跳板]和 skip_while [跳板]处理过邮件消息的头部和正文。但若希望使用相同的底层迭代器同时处理两者怎么办呢?可以通过 by_ref,首先使用 take_while 处理头部,当完成后,获取回底层迭代器,这时 take_while 将恰好在处理消息正文的位置上:
let message = "To: jimb\r\n\
        From: id\r\n\
        \r\n\
        Oooooh, donuts!!\r\n";
let mut lines = message.lines();
// 堆代码 duidaima.com
println!("头部:");
for header in lines.by_ref().take_while(|l| !l.is_empty()) {
    println!("{}", header);
}

println!("\n正文:");
for body in lines {
    println!("{}", body);
}
调用 lines.by_ref() 借用了迭代器的可变引用,而 take_while 迭代器则拥有该引用的所有权。该迭代器在第一个 for 循环结束时超出作用域,意味着借用已经结束,因此可以在第二个 for 循环中再次使用 lines。上例输出:
头部:
To: jimb
From: id

正文:
Oooooh, donuts!!
by_ref 适配器的定义非常简单:它返回迭代器的可变引用。然后标准库中给了个古灵精怪的实现:
impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I {
    type Item = I::Item;
    fn next(&mut self) -> Option<I::Item> {
        (**self).next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (**self).size_hint()
    }
}

换句话说,如果 I 是某种迭代器类型,那么 &mut I 也是一个迭代器,其 next 和 size_hint 方法都由其引用者来处理。对迭代器的可变引用调用适配器时,适配器获取的是引用的所有权,而不是迭代器本身。它只是一个在适配器超出作用域时便会结束的借用。
用户评论