Skip to content

libcore: add defaults for empty iterators #51179

@bergus

Description

@bergus

I'm looking for a way to create empty iterators.

I have a few places in my application where I keep an iterator around as part of a data structure, and will advance that from time to time. After a few rounds, I will reset the iterator to start from the beginning again. (The iterator is supposed to point into the data structure, so I got some problems with implementing that design even though the data is never dropped, but let's ignore that here).
To initialise my structure, I want to create an empty iterator, i.e. one that has no elements left and will only yield None.

pub struct X;
pub struct Example {
   iterator: Once<X>
}
impl Example {
  pub fn reset(&mut self) {
    self.iterator = once(X);
  }
}

let mut e = Example {
  iterator: ??? // how to create a consumed Once?
};
e.iterator.next(); // should yield None
e.reset();
e.iterator.next(); // will yield Option(X)
e.iterator.next(); // will yield None

In this particular case, I can use option::IntoIter directly instead of Once and write

pub struct Example {
   iterator: option::IntoIter<X>
}
impl Example {
  pub fn reset(&mut self) {
    self.iterator = Some(X).into_iter();
  }
}
let mut e = Example {
  iterator: None.into_iter()
};

but that doesn't express my intent as well as using Once. Also, given that in my actual code the iterator type is generic, I would need an additional method get_init next to get_reset in my trait. I'd rather have my trait say that the iterator type needs to implement Default, and the default value should be an instance of the iterator that doesn't yield anything.

My suggestion: Have all builtin iterators implement Default.

For example,

impl<A> Default for Item<A> {
  #[inline]
  fn default() -> Item<A> { Item { opt: None } }
}
impl<A> Default for Iter<A> {
  fn default() -> Iter<A> { Iter { inner: default() } }
}
impl<A> Default for IterMut<A> {
  fn default() -> IterMut<A> { IterMut { inner: default() } }
}
impl<A> Default for IntoIter<A> {
  fn default() -> IntoIter<A> { IntoIter { inner: default() } }
}
impl<T> Default for Once<T> {
  fn default() -> Once<T> { Once { inner: default() } }
}
// (not sure whether all of these could simply be derived)

Does this need to go through the RFC process? Should I simply create a pull request?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-iteratorsArea: IteratorsC-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions