Rustの文でセミコロンを省略してよい条件

Rustの文でセミコロンを省略してよい条件を説明する。

意味論的な原則

Rustのセミコロンは意味と構文からそれぞれ説明できる。意味論的には、以下の原則を覚えておけば十分である。

  • セミコロンで終端された文は強制的に () 型となる。
  • ブロックの途中の文は () 型でなければならない。ブロックの型はブロックの最後の文の型と等しい。(文がひとつもない場合は ())
fn main() {
    let x = { let x = 10; x + 1 }; // x + 1 を返したいので、セミコロンをつけてはいけない
    if true { 1 } else { 0 }; // 構文上は省略できるが、 () 型にするためにセミコロンをつける
    println!("Hello!\n"); // 値を返したいわけではないので、セミコロンをつける
}

構文上の大原則

大原則は、「文同士はセミコロンで区切らなければならない。ただし } で終わる文のセミコロンは省略できる」である。

しかし実際には以下の例外を考慮する必要がある。

例外1: } で終わる式文の場合

文は式文let文文マクロアイテム文 にわかれている。式文は、式をそのまま文とみなすという規則のことである。

if, if let (elseを含む), while, while let, loop, for in, match およびブロック式は } で終わる(これらはC/C++では文だが、Rustでは式であることに注意)。これらの式のパースは、特定条件下で打ち切られる。具体的には、以下の2つの条件を満たしている必要があるようだ。

  • これらの式の直前に別のトークンがパースされていない。例えば、let x = if .., (if .., 1 + if .. は対象外となる。
  • これらの式の直後に ?.some_method(..) が後続しない。例えば、 { }?{ }.f() は対象外となる。

例えば以下の例で、最初の if 文は } でパースが打ち切られている。しかし、次の if 文は ( 10 ) まででひとつの文となる。つまりこの main 関数には3つの文があることになる。

fn f(x: u32) -> u32 { println!("f({})", x); 10 }
fn main() {
    if true { () } else { () } ( 10 );
    1 + if true { f } else { f } ( 10 );
}

(なお、この打ち切り規則はRESTRICTION_STMT_EXPRと呼ばれ、式文のほかに match の各節の右辺にも適用される。)

例外2: let 文の場合

let 文ではセミコロンの省略はできない。これはブロックの末尾でも同様である。

fn main() {
    let x = if true { 0 } else { 0 }; // セミコロンが必要
    let x = 0; // セミコロンが必要
}

例外3: } で終わる文マクロの場合

マクロは {}, (), [] のいずれの括弧でも呼び出せるが、括弧の種類によって構文上の挙動が変わる。文の位置に出現するマクロについては、 {} で呼び出すとセミコロンを省略できる。

fn main() {
    println!{"Hello!"}
    println!{"World!"}
}

ただし、書いたマクロが文マクロとして認識されるか、式マクロとして認識されるかには注意が必要である。具体的には以下の条件でマクロが文マクロと認識される。

  • 文の位置で始まっている。例えば 1 + foo!{ } では foo!{ } は式マクロとして認識される。
  • {} で呼び出されているか、または ; で終端されている。例えば foo!{} - 1;foo!(); - 1; は2つの文として解釈されるが、 foo!() - 1; は1つの文として解釈される。

例外4: } で終わるアイテム文の場合

アイテムのうちセミコロンを必要としないものは、アイテム文でも同様にセミコロンを必要としない。

fn main() {
    struct A {} // セミコロン不要
    let x = A {};
}

まとめ

Rustの文におけるセミコロンは、意味論的には「型を () に強制するために必要」、構文的には「区切り文字として必要。ただし } の直後では不要」という原則を理解すればそれほど難しくはなさそうだ。しかし、実際には構文解析の一貫性等の問題から、この原則に対する例外があることは、記憶の片隅に留めておいてもいいかもしれない。