Home > database >  idiomatic for/else in rust
idiomatic for/else in rust

Time:07-04

in python i can use for/else to check whether or not a for loop terminated at a break statement or finished 'normally':

prod = 1
for i in range(1, 10):
    prod *= i
    if prod > 123:
        break
else:
    print("oops! loop terminated without break.")

is there a simpler/more idiomatic way to do that in rust than this?

let mut prod = 1u64;
let mut found = false;
for i in 1..10 {
    prod *= i;
    if prod > 123 {
        found = true;
        break;
    }
}
if !found {
    println!("oops! loop terminated without break.");
}

there seems to be a discussion about this on rust internals. but that is more about future possibilities than what is idiomatic...

CodePudding user response:

A simple None initialized value provides a reasonably convenient way to do this:

let mut prod = 1u64;
let mut value = None;
for i in 1..10 {
    prod *= i;
    if prod > 123 {
        value = Some(prod);
        break;
    }
}
if value.is_none() {
    println!("oops! loop terminated without break.");
}

CodePudding user response:

I don't know how idiomatic it is but sometimes I write this:

fn main() {
    let mut prod = 1u64;
    let value = 'found: loop {
        for i in 1..2 {
            prod *= i;
            if prod > 123 {
                break 'found Some(prod);
            }
        }
        println!("oops! loop terminated without break.");
        break 'found None;
    };
    //Here value is Option<u64> with the result.
}

That is, an outer labelled loop that can be broken from inside when you are ready. You can even give it a type with the break label value` syntax.

CodePudding user response:

I have seen people use a temporal locale function, Javascript style:

fn main() {
    let mut prod = 1u64;
    let value = (|| {
        for i in 1..10 {
            prod *= i;
            if prod > 123 {
                return Some(prod);
            }
        }
        println!("oops! loop terminated without break.");
        None
    })();
}

You define a temporary function and immediately call it, this way you can have return inside. This trick is also used to propagate errors with ?, while the try {} statement is not stable.

CodePudding user response:

Usually you can translate to some iterator pattern instead of the for loop:

fn main() {
    let mut prod = 1u64;
    if let Some(i) = (1..10)
        .filter_map(|i| {
            prod *= i;
            if prod > 123 {
                Some(i)
            } else {
                None
            }
        })
        .next()
    {
        println!("item found for {i}");
    }
}

Playground

CodePudding user response:

How about this?

let result = {
    for i in 1..10 {
        prod *= i;
        if prod > 123 {
            Ok(())
        }
    }
    Err(())
}
  • Related