Using vec::IntoIter can pass and get the next item, but I don't find a function to get the current (seemingly because the next() function return the current ptr and set self.ptr to the next item in the same time)
We want to iterate throw a vec, sometimes get the current time, sometimes pass to the next one. What is the good way to do this ?
For vec::IntoIter specifically you can call .as_slice() to get a slice with the remaining items. You can then get a reference to the first element to the slice and that will be the "current" element.
As a meta-point here, this is actually a good thing. If iterators had a .Current property (like they do in things like C#) then there'd be no nice way for iterators to return non-clonable things, and they'd end up less efficient for clonable things too.
The iterator API working by returning Option<Item> is great: natural move semantics support, and no ability to look at .Currentwithout having called .MoveNext().
So I have to work with as_slice()[0] or peek() to use the value, and use next() to pass to the next item (because as_slice() return the next item, like Iterator::peekable). I have to review my algorithm but it's ok. Thanks you !
Not necessarily dangerous, but many iterators compute their items on the fly (eg. Range or Repeat, but also Map etc) and there's nothing you could get a reference to, unless all iterators were required to cache a single item just for the "get_current" purposes. This would make all iterators Peekable, in essence, and you couldn't opt out.
I guess that memory-backed iterators specifically could have such a convenience method. But Peekable already exists and works with any iterator.
I'm having trouble understanding your question. Where did you get the word "dangerous"? Are you referring to the MSFT API where they say Current is sometimes undefined? Or do you mean "difficult" rather than "dangerous", and you're referring to the Rust APIs (this was answered by @jdahlstrom above)?
@jumpnbrownweasel : you are right ! "Dangerous" is not the proper word to use. Do you have a link to this undefined behavior on the MSFT API ?
@jdahlstrom : ok it's usefull for certain iterators. In my case my code is a little weird because peek() return the next value --> I have to test the end on peek().
Just to have an example (my code is more complexe , my problem is that I have an iterator of iterators) :
let mut it = v.into_iter().peekable();
while let Some(n) = it.peek() {
for_some_calc += n;
for_some_calc += it.peek().unwrap();
for_some_calc += it.next().unwrap();
}
It would be more "readable" to have something like this :
let mut it = v.magical_current_iterator();
while it.go_next() {
for_some_calc += it.current();
for_some_calc += it.current();
for_some_calc += it.current();
}
So I do this thing, don't know if it's good, certainly naive for the beginner that I am :
pub struct CurrentIter<'a, T> {
v: &'a Vec<T>,
v_pos: usize,
v_first: bool,
}
impl<'a, T> CurrentIter<'a, T> {
pub fn new(v: &'a Vec<T>) -> Self {
Self {
v,
v_pos: 0,
v_first: true,
}
}
pub fn current(&self) -> &T {
if self.v_first {
panic!("Error : go_next is never called");
}
unsafe {
return self.v.get_unchecked(self.v_pos);
}
}
pub fn go_next(&mut self) -> bool {
if self.v_first == false {
self.v_pos += 1;
if self.v_pos < self.v.len() {
return true;
}
// We are at the end
self.v_pos = self.v.len() - 1;
return false;
} else {
if self.v.len() > 0 {
self.v_first = false;
return true; // At the first => No position increment
}
return false; // The vector is empty
}
}
}
The above can be simply written as follows, so can you give a better example? There may be a good way to do what you want with peekable, if you demonstrate it in more detail.
for n in v {
for_some_calc += n;
for_some_calc += n;
for_some_calc += n;
}
Yes , this was not a good example. My apologies. After this discussion I see now that my problem is in fact to iterate throw an Iterator of Iterators <-- this is why I have to get the current value of the parent iterator , or pass to next one when I am at the end of the child iterator.