For-loop Freezes When Encountering Iterator That Was Ended Early. Is This Normal?

65 Views Asked by At

I tried running the below code on rustc 1.72.0 with cargo run :

fn main() {
    let ea = (1..).filter(|x| *x < 10).take(10);

    // Initialize a counter
    let mut count = 0;

    println!("Counter has been initialized.");


    // Iterate through the elements and count them
    for _ in ea {
        count += 1;
        println!("Current index: {}", count);
    }
}

If I'm not mistaken, the expected behavior should be that the program exits normally after printing 1-9, since .take() is supposed to stop early and return all elements if the number of iterator elements is less than .take()'s specified parameter (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take).

However, what happened was that my program got frozen with items 1-9 printed out, and I had to press Ctrl+C to exit.

enter image description here

I believe it is also worth noting that cargo check found no issues with the code: enter image description here

Additionally, creating the iterator with let ea = (1..10); instead caused the same program to exit normally after printing values 1-9.

enter image description here

Is this expected behavior from Rust? If it is, may I know what is causing it, and whether it will be changed in the future?

2

There are 2 best solutions below

10
Chayim Friedman On

It does not freeze, it just overflows. Since the iterator only has 9 elements < 10, it counts all the way to i32::MAX then overflows back to 0. In debug builds, this will panic. In release builds, it will wrap around and give you 0 ad the tenth element.

0
Ivan C On

A slightly different angle than provided by @ChayimFriedman is this:

// This is an iterator that starts at 1 and increments it by one forever
let it = 1..;

// This iterator is still infinite, but will only yield items that satisfy the filter
let it = it.filter(|x| *x < 10);

// This iterator will yield first 10 elements form the underlying infinite iterator
let it = it.take(10);