I stared at this error for 30 minutes.
fn main() { loop { break; } println!("done"); } Why does Rust want me to return? I am inside a loop {}. I just want to break.
Turns out, I forgot a semicolon.
Rust is expression-oriented
In Rust, almost everything is an expression. And the rule is simple but easy to forget:
If the last line has NO semicolon, its value is returned.
If the last line HAS a semicolon, it becomes().
That () is the unit type. Empty. Nothing.
Look at this:
let a = { 5 }; // a = 5 let b = { 5; }; // b = () One character. Completely different value.
Where it hurts: loop
This is where I got hit.
1. Loop in the middle of a function needs ;
If the loop is not the last thing, you must close it.
fn main() { loop { // do something break; }; // <- this ; is mandatory println!("now we continue"); } Without it, Rust sees two expressions back-to-back with no separator and gets confused.
2. Loop at the end of a function must NOT have ; if you want to return its value
This is the part the Rust Book says in one line and moves on.
fn get_number() -> i32 { loop { break 42; } // <- NO semicolon, so 42 is returned } If I add a semicolon there:
fn get_number() -> i32 { loop { break 42; }; // <- this is now () } The function promises to return i32, but I just returned (). Compiler error.
So if you use ;, you discard the value. If you want to keep the value, the last row must NOT have ;.
3. break vs return inside loop
This also confused me.
loop { break 10; // exits only the loop, value 10 } loop { return 10; // exits the whole function } If you just want to get out of the loop with a value, use break with a value and leave the last line without a semicolon.
The rule I will remember
- Need the value? Last row, no semicolon.
- Just running a statement? Add semicolon, it becomes
().
