Early-breaking from Rust's match

一世执手 提交于 2020-07-29 12:19:06

问题


I want to switch through many possible cases for x and there's one case (here x == 0) where I want to check the result of some additional code to determine what to do next. One possibility is to return early from the match.

I'd use break to do this early-returning in C, but this isn't allowed in Rust. return returns from the parent function (in this case main()) and not from the match only (i.e. the println! at the end isn't run!).

I could just negate the sub-condition (here y == 0) and indent the whole lot of following code -- but I find this ugly and unreadable.

Putting the sub-condition into a match-guard is no option for me since it's simply too big.

Is this possible in Rust or is there a better alternative (except creating another subfunction or other work-arounds)?

Minimal example:

fn main() {
    let x = 1;

    match x {
        1 => {
            let y = 0;
            /*
             * do ev1l stuff to y that I don't want to put into the match-guard
             * as it's simply too much.
             */

            /* break early ... */
            if y == 0 {break;} // > error: `break` outside of loop [E0268]

            assert!(y != 0, "y was 0!");
            /* do other stuff in here. */
        }
        _ => {}
    }

    println!("done matching");
}

I found Mixing matching, mutation, and moves in Rust — is it wrong?

match embraces both imperative and functional styles of programming: you can continue using break statements, assignments, et cetera, rather than being forced to adopt an expression-oriented mindset.

I'm still learning Rust and coming from C so bear with me ;-)


回答1:


You could create a macro like

macro_rules! block {
    ($xs:block) => {
        loop { let _ = $xs; break; }
    };
}

and do

match x {
    1 => block!({
        ...
        if y == 0 { break; }
        ...
    })
    _ => {}
}

It's not an amazing solution, but it is semantically meaningful.




回答2:


You can wrap the match into a loop that only runs once and break out of the loop

fn main() {
    let x = 1;

    loop { match x {
        1 => {
            let y = 0;
            /*
             * do ev1l stuff to y that I don't want to put into the match-guard
             * as it's simply too much.
             */

            /* break early ... */
            if y == 0 { break; }

            assert!(y != 0, "y was 0!");
            /* do other stuff in here. */
        }
        _ => {}
    } break; }

    println!("done matching");
}



回答3:


Something else you could do is make a "self-executing" closure and use a return statement inside. I don't know whether there are any weird performance characteristics of this but syntactically it's pretty clean.

fn main() {
    let x = 1;

    // This closure is just used to catch the "return" statement.
    (|| {
        match x {
            1 => {
                let y = 0;
                /*
                 * do ev1l stuff to y that I don't want to put into the match-guard
                 * as it's simply too much.
                 */

                /* break early ... */
                if y == 0 { return; } // Ok!

                assert!(y != 0, "y was 0!");
                /* do other stuff in here. */
            }
            _ => {}
        }
    })();

    println!("done matching");
}

Here's a playground link showing it working.



来源:https://stackoverflow.com/questions/37814942/early-breaking-from-rusts-match

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!