如何检查for循环是否在迭代器的最后一个元素上?

问题描述

我试图找到一种方法来检查我是否在 for 循环中的迭代器的最后一个元素上,而不使用 .clone();目前我正在这样做:

let sentence = "The quick brown fox.";
let words = sentence.split(' ');
let last = words.clone().last().unwrap();
 
for word in words {
    if word == last {
        print!("{}",word);
    }
} 

我也尝试在迭代器上使用 .collect() ,但这需要我使用 .iter().enumerate() 来检查最后一个索引,这对我来说似乎不必要地复杂:

let sentence = "The quick brown fox.";
let words: Vec<&str> = sentence.split(' ').collect();
 
for (i,word) in words.iter().enumerate() {
    if i == words.len() - 1 {
        print!("{}",word);
    }
}

有没有办法以更简洁的方式做到这一点,也许只是使用原始迭代器?

解决方法

将您的迭代器转换为 Peekable

这将需要将迭代脱糖为 while let,但如果在迭代期间 peek() 返回 None,则您处于最后一次迭代:

let mut it = sentence.split(' ').peekable();
while let Some(word) = it.next()  {
    if it.peek().is_none() {
        println!("{}",word);
    }
}

Playground

,

对于有限迭代器的一般情况,如果你想获得最后一项,你可以按照@Masklinn(见他们的答案)的建议,转换为一个 Peekable ,它会缓冲所以它总是知道下一个元素。

在您的确切情况下,当您只想打印最后一个单词而不关心其他单词时, 有一个便宜得多的解决方案,因为拆分字符实现了 {{1} }.

所以很容易得到最后一个词,您不必收集整个拆分或枚举。它也很快,因为将从末尾开始搜索字符串并且不会复制任何内容。

所以你可以这样做

DoubleEndedIterator
,

您可以利用 Iterator::map() 迭代器适配器来实现更方便的使用:

let sentence = "The quick brown fox.";
let words: Vec<&str> = sentence.split(' ').collect();

for (word,is_last_element) in words.iter().enumerate()
  .map(|(i,w)| (w,i == words.len() - 1))
{
   if is_last_element {
      println!("{}",word);
   }
}

这样,您不必处理循环体中的索引,而只需关注特定迭代中的给定元素是否是最后一个。