Return expressions is a expression,Why add a semicolon after an return expression?

https://doc.rust-lang.org/stable/reference/expressions/return-expr.html#return-expressions

return a is ok
why <return a;>?
why <;> ?
#############################################

Syntax
ReturnExpression :
return Expression?

Return expressions are denoted with the keyword return. Evaluating a return expression moves its argument into the designated output location for the current function call, destroys the current function activation frame, and transfers control to the caller frame.

An example of a return expression:

fn max(a: i32, b: i32) -> i32 {
if a > b {
return a;
}
return b;
}

The "return expression" returns never !, iirc, and a block returns a unit (), they are not the same type.

Consider the following code:

fn accept_i32(_val: i32) {}

fn main() {
    accept_i32({ return; });
    accept_i32({ return });
    accept_i32(return);
    // cannot compile
    // accept_i32({});
}

Edit:

Maybe I misunderstood the OP. In OP's code the semicolon is actually optional, it's just a matter of code style.

Read the pinned code formatting post.


There's no need for the semicolons in the example. The semicolon on the return a; looks slightly better to me, as there's no reason to "pass a value" out of the block, but it's not a big deal at all.

There's no need to use return b instead of just b either. That second return is not idiomatic.

// This still works
fn max(a: i32, b: i32) -> i32 {
    if a > b {
        // I'd personally put a `;` here but no biggie
        return a
    }
    b
}

This is even more idiomatic...

fn max(a: i32, b: i32) -> i32 {
    if a > b { a } else { b }
}

...but the example is trying to demonstrate return, and not trying to be idiomatic.

2 Likes

rust-reference document say:
add semicolons is statement
del semicolons is expression
and say:
return is a expression
then give the example:

fn max(a: i32, b: i32) -> i32 {
if a > b {
return a;
}
return b;
}

return is an expression
but he add the semicolons....

Sure.

//  vvvvvvvv return expression
    return a ;
//  ^^^^^^^^^^ expression statement

Is there a further question?

for expression statement:
normal expression statement: x + 1; it don't return value.
special expression statement: return x + 1; it can return value.
i 'm a little confuse
because rust say statement don't return value
return x + 1; is statement, but it can return value
isn't it better to remove the semicolon in rust-reference
this makes it a bit diffcult for me to understand... :mask:

are you saying that writing a semicolon after the return expression is just for the beautiful?
i don't need to care it?
so when i'm coding on a daily baisis
if i use return, i will just follow my style without adding a semicolon, right?

In everyday code you don't need to worry about it.

If you're just trying to figure out how to code Rust on a daily basis, the book may be a better resource than the reference.


I wrote these parts before your last comment. Usually things just work and you don't need to know these details. If it's confusing or too much right now, don't worry about understanding it, you don't need to understand anything extra to code on a daily basis.

Anyway --

The expression returns before the statement "completes".

if a > b  // vvvvv This block has type () -- does not end with ;
  {  // -----------------------------------------------------+
      return a  // This expression returns; it has type !    |
      ; // This statement has type ()                        |
  } // ------------------------------------------------------+
// ...

! is the "never type" that @Embers-of-the-Fire mentioned.

Now you may ask, why does this work:

if a > b  // vvvvv This block has type () (does not end with ;)
  {  // -----------------------------------------------------+
      return a  // This expression returns; it has type !    |
  } // ------------------------------------------------------+

And the reason is that ! is special: It can coerce to any other type, including ().


In fact it's a bit stronger than that: the compiler understands that control flow can't proceed past a !, and thus the entire containing block can be coerced... but this is only permitted when there is no tail expression.

    //                 this if/else has type f64
    let _ = if a > b // -----------------------------------------------+
      {  // ------------------------------------------------+ block    |
        return a // expression returns; has type !          | coerces  |
        ;        // statement has type ()                   | to type  |
        71       // unreachable expression with type i32    | f64      |
        ;        // statement has type ()                   | thanks   |
      } // -------------------------------------------------+ to the ! |
      else //                                                          |
      { // --------+ this block has type f64                           |
        0.0 //     | (both branches must have the same type)           |
      } // --------+                                                   |
     // ---------------------------------------------------------------+
      ; // statement has type ()

(Playground.)

If you add a tail expression -- even () -- it doesn't compile.


I'm not sure if the reference covers this.

1 Like

Thanks... :+1: :+1:

In practice, rust-analyser will tell you when you forgot a semicolon or accidentially placed one. That way, you'll quickly get tha hang of it.