3 ms·
All the time. A block (in the general sense so that includes function) which ends with an expression will have that expression’s value as its own value (/ retur
by masklinn 2y ago
All the time. A block (in the general sense so that includes function) which ends with an expression will have that expression’s value as its own value (/ return). A `;` converts the trailing expression into a statement, which does not have a value, and thus the block returns `()` (the something representing nothing).
Method chaining is also common in Rust, because builders are common, and chains of iterator adapters are common, and chains on monadic structures (option/result) are common, … having every line break implicitly insert a `;` would be horrid.
- notpushkin 2y agoWait, so this is legal: fn five() -> i32 { 5 } and this isn't? fn five() -> i32 { 5; } I can't tell if I'm amazed or terrified.
- deleted 2y ago[deleted]
- jihiggins 2y agothis is what those end up being, it's pretty straightforward? fn five() -> i32 { return 5; } fn five() -> i32 { 5; return (); } semicolon changes the expression from returning the result of the expression to running the expression and returning the unit type. if you accidentally do that and specified a non-unit-return-type in the function signature, the type checker tells you about it: error[E0308]: mismatched types --> src/main.rs:1:14 | 1 | fn test() -> i32 { | ---- ^^^ expected `i32`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression 2 | 5; | - help: remove this semicolon to return this value which is also pretty clear about the solution
- masklinn 2y agoYes. > I can't tell if I'm amazed or terrified. The rule is very simple and obvious, and the compiler will yell at you if you get it wrong. It's also very useful and even critical of how expression-oriented the language is: an `if/else` or a match statement must typecheck, all branches have to have the same type. It's obvious if you're using it as an expression, but it doesn't go away if you're using it for the side-effect (as an imperative conditional/switch) and then things can get more dicey as the expressions in each branch can have different types. `;` solves that by making every branch `()`-valued.
- notpushkin 2y agoOkay, this is really neat design. I went to check whether if..else works in an expression context and it does: fn five() -> i32 { let a = if (true) { 3 } else { 6 }; return a + 2; } Pure fun!
- masklinn 2y agoYa if you want fun match/case also works like that. And though for abs while don’t (they always return ()) `loop` itself does, you can `break` with a value and that’s what comes out the loop.