Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can a Rust struct be defined without a semicolon?

Tags:

rust

I'm learning Rust and the chapter for structs gives an example of a struct without a ; at the end. It compiles but I have no idea why this is allowed.

fn main() {
    struct User {
        username: String,
        email: String,
        sign_in_count: u64,
        active: bool,
    }
}

... same question goes for functions, actually.

like image 311
George Shuklin Avatar asked Mar 08 '23 16:03

George Shuklin


1 Answers

As Shepmaster said in the comment, the "reason" is that Rust defines so. Here I will explain the rules behind it.

Basically you can omit ; when it ends with }. This will answer your question.

However, there are a number of exceptions to the rule:

When {} appears indirectly

The rule above doesn't apply when {} appears indirectly, like

use std::io::{self, Read, Write}; // Here }; appears

or

let x = if cond {
    1
} else {
    2
}; // Here }; appears

In this case, {} isn't a direct part of use/let. So in this case you need ;.

Items

Items are things which you can also place outside of functions. That is, one of extern crate, use, mod, struct, enum, union, type, trait, impl, fn, static, const, extern, and macros.

You can place items either outside of functions or in a function. However, There is a difference between them:

  • If it appears outside of functions, you have to omit ; when unnecessary.
  • If it appears in a function, you can also place ; there. This is basically because the ; itself is an empty statement.

Example:

struct A {} // You can't place ; here
fn main() {
    struct B {} // You can omit ; here
    struct C {}; // You can also place ; here
}

The last expression

You have to omit ; if

  • It is the last statement in the block,
  • it is an expression (items and let aren't expressions), and
  • you want to return the value from the expression.

Example:

fn f() -> i32 {
    let x = 1;
    x + x // You want to return x + x, so you can't place `;` here
}

Block expressions

if, if let, match, loop, while, while let, for, unsafe, and bare {} ends with }, so you can omit ; after them. However, there is a slight effect if you place ; here.

Example:

fn f(x: i32) -> i32 {
    if x < 10 {
        10
    } else {
        20
    }; // If you remove ; here, then you will see a compile error.
    42
}

In most cases, you don't have to place ; here; instead you may have to place ; in the blocks.

fn f(x: i32) -> i32 {
    if x < 10 {
        10;
    } else {
        20;
    }
    42
}

Statement macros

In statement positions, you can write three different kinds of macros:

  • some_macro!()/some_macro![]: this isn't in fact a statement macro; instead, this is a mere expression macro. It can't expand to items or let.
  • some_macro!{}: this expands to zero or more statements.
  • some_macro!();/some_macro![];/some_macro!{};: this also expands to zero or more statements; however, there is a very minor difference: ; is added to the last expanded statement.
like image 147
Masaki Hara Avatar answered Mar 15 '23 21:03

Masaki Hara