Hone logo
Hone
Problems

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 Iterator trait for a struct named RangeIterator.
  • The RangeIterator struct should have a start field (i32), an end field (i32), and a step field (i32).
  • The next() method of the iterator should return an Option<i32>.
    • Some(value) if the next value in the sequence is available.
    • None when the iterator has reached the end of the sequence.
  • The iterator should correctly handle cases where the step is positive, negative, or zero.
  • The iterator should not panic if the end value is never reached given the start and step.

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 return None.
  • step == 0: The iterator should immediately return None.
  • step is positive and start is greater than end: The iterator should immediately return None.
  • step is negative and start is less than end: The iterator should immediately return None.
  • Large values of start, end, and step that 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, and step are all i32 integers.
  • 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 Iterator trait, which requires a next() method that returns an Option<Self::Item>.
  • Consider how to handle the condition where the end value is never reached given the start and step. 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 return None.
  • This is a good exercise to solidify your understanding of Rust's ownership and borrowing rules within the context of iterators.
Loading editor...
rust