Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust skip loop on "None" else move forward with computation

Tags:

idioms

rust

I have a nested loop where I want to check if a certain condition holds on a table of usize values. However, the table may only be partially filled -- so it is actually a table of Option<usize> variables. When at least one of the values is missing, I do not consider the condition to be violated, and therefore want to continue on with the next set of values.

Currently I do it as follows:

for i in 0..n {
    for j in 0..n {
        for k in 0..n {
            let v_ij = match table[i][j] {
                None => { continue; },
                Some(val) => { val }
            };

            let v_jk = match table[j][k] {
                None => { continue; },
                Some(val) => { val }
            };

            let res_left = match table[v_ij][k] {
                None => { continue; },
                Some(val) => { val }
            };

            let res_right = match table[i][v_jk] {
                None => { continue; },
                Some(val) => { val }
            };

            if res_left != res_right {
                return false;
            }
        }
    }
}

(For context: the computation is checking whether a partial magma is associative, but this is not important for the question.)

Is there an idiomatic way to replace all these matches? In Haskell, using the Maybe monad, I believe I could wrap this piece of code up into a do block, so that None values are automatically propagated. I tried using table[i][j].unwrap_or({continue;}) but this evaluates the continue greedily; using table[i][j].unwrap_or_else({continue;}) gives a syntax error.

like image 421
Mees de Vries Avatar asked Feb 26 '26 07:02

Mees de Vries


1 Answers

In such a case, to limit repetition and to improve clarity, I would probably use a macro:

macro_rules! unwrap_or_continue {
    ($opt: expr) => {
        match $opt {
            Some(v) => v,
            None => {continue;}
        }
    }
}

There is loop_unwrap crate that implement something similar but more complex.

Thus each of your test would be reduced:

for i in 0..n {
    for j in 0..n {
        for k in 0..n {
            let v_ij = unwrap_or_continue!(table[i][j]);
            let v_jk = unwrap_or_continue!(table[j][k]);
            let res_left = unwrap_or_continue!(table[v_ij][k]);
            let res_right = unwrap_or_continue!(table[i][v_jk]);
            if res_left != res_right {
                return false;
            }
        }
    }
}

like image 183
Denys Séguret Avatar answered Feb 28 '26 12:02

Denys Séguret



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!