- Feature Name: iter_from_closure
- Start Date: 2017-09-03
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
Summary
Add a function iter_from_closure for quickly transforming a mutable closure of the right form into an Iterator.
In other words, the semantics are:
fn iter_from_closure<Item, F>(closure: F) -> impl Iterator<Item = Item>
where F: FnMut() -> Option<Item>
Motivation
Sometimes, you have some state, and from that, you need to create an Iterator, but only once - and never for reuse.
In such circumstances, it is not ergonomic to create a new struct just to hold the relevant state and then impl Iterator for that struct and then instantiate the struct.
A more ergonomic solution is to simply take any state you already have, capture it in an FnMut() -> Option<Item> and then let that closure implement Iterator<Item = Item>. Unfortunately, it is not possible for FnMut() -> Option<Item> to directly implement Iterator<Item = Item>.
Detailed design
Create a function iter_from_closure which returns an object implementing Iterator<Item = Item>:
// [bikeshed] iter_from_closure
fn iter_from_closure<Item, F>(closure: F) -> MutFn<Item, F>
where
F: FnMut() -> Option<Item>
{
MutFn::new(closure)
}
where:
// [bikeshed] MutFn
struct MutFn<Item, F>
where
F: FnMut() -> Option<Item>
{
closure: F
}
impl<Item, F> MutFn<Item, F>
where
F: FnMut() -> Option<Item>
{
fn new(closure: F) -> Self {
MutFn {
closure
}
}
}
impl<Item, F> Iterator for MutFn<Item, F>
where
F: FnMut() -> Option<Item>
{
type Item = Item;
fn next(&mut self) -> Option<Self::Item> {
(self.closure)()
}
}
The function iter_from_closure can then be used as in:
fn main() {
let mut count = 10;
let iter = iter_from_closure(|| {
let c = count;
count = c - 1;
if c > 0 { Some(c) } else { None }
});
println!("{:?}", iter.collect::<Vec<_>>());
}
The function MutFn::new is not meant to be stabilized at this time. Instead, the public API is iter_from_closure.
How We Teach This
Documentation on iter_from_closure and possibly MutFn should be enough.
Drawbacks
This could be done in an external crate - it could be considered bloat in core.
Alternatives
- Implement this in an external crate.
Unresolved questions
- Should
impl Iterator<Item = Item> be used instead? Currently, conservative_impl_trait will take much longer to stabilize, so will iter_from_closure take as long to stabilize?
- Is this needed given the work on generators / co-routines?