How to refactor a loop with iterator. (Returning from closure)

65 views Asked by At

I want to refactor a function and use an iterator rather than a for loop. I have exemplified the problem with the following demo code to be refactored:

fn with_loop() -> bool {
    let foo = [1, 2, 25, 4, 5];
    let mut sum = 0;
    for bar in foo {
        if bar > 20 {return false;}
        sum += bar;
    }
    sum > 10
}

I want to do something like the following, the problem is I cannot return from a closure of course.

fn functional_programming() -> bool {
    let foo = [1, 2, 25, 4, 5];
    let sum: i32 = foo
        .into_iter()
        .inspect(|bar_ptr| {
            if *bar_ptr > 20 {
                // functional_programming() returns false;
                print!("I want to return false");
            }
        })
        .sum();
    sum > 10
}

Some extra constraints which I would prefer not to negotiate:

  1. Scanning the iterable just once
  2. Avoid collecting and reopening the iterator
  3. Avoid too much nesting in the callbacks
2

There are 2 answers

6
aedm On BEST ANSWER

"sum() can be used to sum any type implementing Sum, including Option and Result."

fn functional_programming() -> bool {
    let foo = [1, 2, 25, 4, 5];
    let sum = foo
        .iter()
        .map(|i| if *i > 20 { Err(()) } else { Ok(*i) })
        .sum::<Result<i64, _>>();
    let Ok(sum) = sum else {
        return false;
    };
    sum > 10
}

Playground

2
Kaplan On

IMHO is ControlFlow much better suited:

fn functional_programming() -> bool {
    let foo = [1, 2, 25, 4, 5];
    let ControlFlow::Continue(sum) = foo.iter().try_fold(0, |sum, &bar| {
        if bar > 20 {
            return ControlFlow::Break(sum);
        }
        ControlFlow::Continue(sum + bar)
    }) else { return false; };
    sum > 10
}

Playground