Start learning free

LESSON 140 OF 414 · LOOPS & CONDITIONALS

Check for Positive Numbers in Rust: Fixing the Buggy Code

Practice Read the full explanation

Inside the code editor we've tried to write a function that takes a vector nums as argument and returns true if there exists at least one positive (greater than zero) number in the vector; returns false otherwise.

So when we called the function for vec![-1, 2, 3], we expected our code to print:

Array has positive numbers

but it seems like we made some mistakes: the compiler rejects our code with a mismatched types error (expected bool, found ()), and even once that is fixed, the code would print:

Array doesn't have positive numbers

Assignment:

Your task is to fix our function.

STEP 1 OF 1
    Ctrl + Enter to check

    RUST · LOOPS & CONDITIONALS

    Buggy Code Check For Positive Numbers in Rust, explained

    What the code is supposed to do

    The function check_for_positive receives a vector of integers and returns true if at least one of them is greater than zero, and false if none is. The program that calls it prints Array has positive numbers for [-1, 2, 3]. This is the code you start with:

    fn check_for_positive(nums: Vec<i32>) -> bool {
        for number in nums {
            if number > 0 {
                return true;
            } else {
                return false;
            }
        }
    }
    
    // Do not change this code:
    fn main_function() {
        if check_for_positive(vec![-1, 2, 3]) {
            println!("Array has positive numbers");
        } else {
            println!("Array doesn't have positive numbers");
        }
    }
    

    The Rust compiler rejects it with error[E0308]: mismatched types. It says that a bool was expected and () was found, and it adds that for loops evaluate to the unit type ().

    What goes wrong

    The logic bug: giving up after the first element

    Both branches of the if contain a return. So the loop never gets to look at a second element: whatever the first number is, the function answers immediately. For [-1, 2, 3] the first number is -1, which is not positive, so the else branch returns false without ever seeing the 2 and the 3.

    One number that is not positive says nothing about the others. The question is whether any element is positive, and the answer false is only justified once every element has been checked.

    The compile error: no value after the loop

    The function promises a bool. The body ends with the for loop, and a loop produces no value, only (). The compiler can't prove that the loop always returns, because it can't be sure the vector is non-empty. For an empty vector the loop would finish at once, and the function would have nothing to return. That is the mismatch the error describes.

    Both problems have the same cure: the else branch goes away, and a final false is added after the loop.

    Fixing it step by step

    1. Remove the else branch. A non-positive number should simply let the loop continue with the next element.
    2. Keep return true inside the if. One positive number is enough to answer, so the function can stop immediately.
    3. Add return false after the loop. It runs only if the loop finished without finding a positive number, including for an empty vector.

    The fixed code in Rust

    fn check_for_positive(nums: Vec<i32>) -> bool {
        for number in nums {
            if number > 0 {
                return true;
            }
        }
        return false;
    }
    
    fn main_function() {
        if check_for_positive(vec![-1, 2, 3]) {
            println!("Array has positive numbers");
        } else {
            println!("Array doesn't have positive numbers");
        }
    }
    

    For [-1, 2, 3]: -1 is not positive, so the loop moves on. 2 is positive, so the function returns true and the program prints Array has positive numbers. For [-1, -2] no element qualifies, the loop ends, and the function returns false.

    Tracing both versions

    Following the original code on [-1, 2, 3] shows the logic bug directly. The loop starts with number = -1. The test -1 > 0 is false, so the else branch runs and returns false. The function is finished after one pass, and 2 and 3 are never read.

    In the fixed version, the same first pass finds the test false and does nothing, because there is no else. The second pass has number = 2, the test is true, and the function returns true. The third element is never read, but it doesn't need to be.

    The worst case for the fixed version is a vector with no positive number. Every element is checked, the loop ends, and the line after it returns false.

    The same idea with an iterator

    Rust has a ready-made form of this search. nums.iter().any(|&x| x > 0) returns true as soon as one element passes the test, and false when none does, with the same result on every vector, including an empty one. For vec![-1, 2, 3] it gives true, for vec![-1, -2] it gives false, and for an empty vector it gives false. The lesson uses the explicit loop, which shows what any does for you.

    Rust details

    • Everything is an expression. A function's body evaluates to its last expression. A for loop is an expression of type (), so a function that ends with one can't have a return type other than ().
    • Adding only the final false is not enough. It would make the code compile, but the early return false would remain, and [-1, 2, 3] would still give false. Both problems have to be fixed.
    • return false; versus false. Writing false without a semicolon on the last line is the idiomatic form, and it means the same as the lesson's return false;.
    • The vector is consumed. for number in nums moves the vector into the loop, and each number is an i32 that needs no dereference.

    Common mistakes

    • Returning false inside the loop. It reports the answer for the first element only.
    • Treating "not positive" as a final answer. Only the positive case ends the search early. The negative case means "keep looking", and that asymmetry is what the fixed loop expresses.
    • Assuming the compiler error is the whole bug. Silencing the error with a closing false makes the program build but leaves the wrong answer for [-1, 2, 3]. After a fix compiles, run the example to check the result.
    • Using >= 0. Zero is not positive, so [0] must give false.
    • Printing instead of returning. The function returns a bool, and main_function does the printing.

    Testing

    • [-1, 2, 3] gives true.
    • [-1, -2, -3] gives false.
    • [0] gives false.
    • [] gives false.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free