Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exit from a block expression? (similar to function "return")

Tags:

rust

Returning from functions before reaching the last statement can be done using "return", for example:

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

    0 // this line is never reached
}

Is it possible to do something similar with block expressions? Example:

let foo = {
    if true {
        *something to exit with 1*
    }

    0 // this line is never reached
};

Thanks for any help.

P.S. I know in this simple example I could have used the "if-else" expression. I'm asking about block expressions in general, not this example in particular :)

like image 485
Augustinas Avatar asked Mar 14 '21 20:03

Augustinas


4 Answers

For stable Rust, there is a well known "loop hack":

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

        break 0;
    };
}

For nightly, there is an unstable feature label_break_value that does just that:

#![feature(label_break_value)]

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

        0 // this line is never reached
    };
}

It doesn't seem obvious by looking at the Github issues whether this feature will ever be stabilized. It has been implemented for over 2 years, but it doesn't seem to have enough supporters to move forward.

like image 151
mcarton Avatar answered Oct 19 '22 22:10

mcarton


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.

like image 34
justinas Avatar answered Oct 19 '22 22:10

justinas


No, there is no mechanism to yield early from a block.

Interesting though, this mechanism has been proposed. Attempting to do so with the break-label syntax (used in loops) will result in the error:

let foo = 'a: {
    if true {
        break 'a 1;
    }
    0
};
error[E0658]: labels on blocks are unstable
 --> src/main.rs:2:13
  |
2 |     let s = 'a: {
  |             ^^
  |
  = note: see issue #48594 <https://github.com/rust-lang/rust/issues/48594> for more information

So this will work on the nightly compiler with #![feature(label_break_value)]. However, I wouldn't hold your breath on it being stabilized anytime soon.

like image 33
kmdreko Avatar answered Oct 19 '22 20:10

kmdreko


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

like image 40
sebpuetz Avatar answered Oct 19 '22 21:10

sebpuetz