Is there a way to "return" from a block expression?
Asked Answered
P

4

30

You can return from a function before reaching the last statement can be done using return:

fn example() -> i32 {
    if true {
        return 1;
    }

    0 // this line is never reached
}

Is it possible to do something similar with block expressions?

let foo = {
    if true {
        // somehow "return" so that foo is 1
    }

    0 // this line is never reached
};

In this example I could have used an if-else, but I'm asking about block expressions in general.

Phore answered 14/3, 2021 at 20:46 Comment(1)
@AlexeyLarionov because using "return 1" inside a block expression returns from the entire function the expression is in, not just the expression. If you're asking "why not use a function", readabilityPhore
L
36

From Rust 1.65.0, it is possible to name the block and break from it:

fn main() {
    let foo = 'bar: {
        if true {
            break 'bar 1;
        }

        0 // this line is never reached
    };
}

Before Rust 1.65.0, there was a well known "loop hack":

fn main() {
    let foo = loop {
        if true {
            break 1;
        }

        break 0;
    };
}
Library answered 14/3, 2021 at 21:11 Comment(4)
Can the loop hack be used to break the hacky outer loop from within a legit inner loop? Something like break 'outer value;?Farceuse
@Farceuse no, you'd need labels for that.Library
FYI: cargo clippy complains about the loop hack; it says "this loop never actually loops".Taciturn
You can now break from a labeled block since 1.65.0 blog.rust-lang.org/2022/11/03/Rust-1.65.0.htmlLillia
K
12

You could also use an immediately invoked closure.

fn main() {
    let foo = (|| {
        if true {
            return 1;
        }
        
        0
    })();
}

My bet would be that LLVM is smart enough to optimize the function call out in release builds.

Kall answered 14/3, 2021 at 21:26 Comment(1)
This is a good hack. Might it have issues with needing to move variables into the closure though?Farceuse
S
8

Edit: This feature has been stabilized in Rust 1.65.0.


This feature has been proposed: RFC 2046 - break label value. It uses the break-label syntax (used in loops) and is available as an unstable feature.

So this will work on the nightly compiler:

#![feature(label_break_value)]

let foo = 'a: {
    if true {
        break 'a 1;
    }
    0
};
Soelch answered 14/3, 2021 at 21:6 Comment(0)
K
5

Edit: It's now possible to break from labeled blocks


Original answer:

I don't think it's currently possible but I found this tracking issue: https://github.com/rust-lang/rust/issues/48594

Kandis answered 14/3, 2021 at 21:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.