Implementing Basic Iterators in Rust
This challenge focuses on understanding and implementing the fundamental concepts of iterators in Rust. Iterators are a core feature of Rust, enabling efficient and flexible traversal of collections. By implementing a simple iterator, you'll gain a deeper understanding of how Rust's iteration mechanism works.
Problem Description
You are tasked with creating a custom iterator that yields a sequence of numbers from a given starting value up to (but not including) an ending value, with a specified step. This iterator should adhere to the Iterator trait in Rust. Your iterator should be able to handle positive, negative, and zero step values correctly. The iterator should not panic if the ending value is never reached given the starting value and step.
Key Requirements:
- Implement the
Iteratortrait for a struct namedRangeIterator. - The
RangeIteratorstruct should have astartfield (i32), anendfield (i32), and astepfield (i32). - The
next()method of the iterator should return anOption<i32>.Some(value)if the next value in the sequence is available.Nonewhen the iterator has reached the end of the sequence.
- The iterator should correctly handle cases where the
stepis positive, negative, or zero. - The iterator should not panic if the
endvalue is never reached given thestartandstep.
Expected Behavior:
The iterator should produce a sequence of numbers that increment (or decrement) by the specified step from the start value until it reaches (or crosses) the end value. The end value itself should not be included in the sequence.
Edge Cases to Consider:
start == end: The iterator should immediately returnNone.step == 0: The iterator should immediately returnNone.stepis positive andstartis greater thanend: The iterator should immediately returnNone.stepis negative andstartis less thanend: The iterator should immediately returnNone.- Large values of
start,end, andstepthat could potentially lead to integer overflow. (While overflow handling isn't strictly required, consider its implications).
Examples
Example 1:
Input: RangeIterator { start: 0, end: 5, step: 1 }
Output: Some(0), Some(1), Some(2), Some(3), Some(4), None
Explanation: The iterator yields numbers from 0 to 4, incrementing by 1.
Example 2:
Input: RangeIterator { start: 5, end: 0, step: -1 }
Output: Some(5), Some(4), Some(3), Some(2), Some(1), None
Explanation: The iterator yields numbers from 5 to 1, decrementing by 1.
Example 3:
Input: RangeIterator { start: 2, end: 10, step: 2 }
Output: Some(2), Some(4), Some(6), Some(8), None
Explanation: The iterator yields even numbers from 2 to 8.
Example 4:
Input: RangeIterator { start: 10, end: 2, step: 2 }
Output: None
Explanation: Start is greater than end and step is positive, so no values are yielded.
Constraints
start,end, andstepare alli32integers.- The iterator should be reasonably efficient. Avoid unnecessary computations within the
next()method. - The iterator should not panic under any valid input conditions.
Notes
- Remember to implement the
Iteratortrait, which requires anext()method that returns anOption<Self::Item>. - Consider how to handle the condition where the
endvalue is never reached given thestartandstep. The iterator should simply stop yielding values in this case. - Think about the logic required to determine when to return
Some(value)and when to returnNone. - This is a good exercise to solidify your understanding of Rust's ownership and borrowing rules within the context of iterators.