Go言語入門:言語仕様 -Vol.8-

スポンサーリンク
Go言語入門:言語仕様 -Vol.8- ノウハウ
Go言語入門:言語仕様 -Vol.8-
この記事は約12分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語の言語仕様について解説しています。

スポンサーリンク

背景

Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。

言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。

そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。

言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!

Semicolons(セミコロン)

形式的な構文では、多くの生成規則において終端記号としてセミコロン";"を使用します。Goプログラムは、以下の2つのルールを使用して、これらのセミコロンのほとんどを省略できます。

  1. 入力がトークンに分割される際、行の最後のトークンが以下のいずれかである場合、トークンストリーム内のそのトークンの直後に自動的にセミコロンが挿入されます。
    • 識別子
    • 整数、浮動小数点、虚数、ルーン、または文字列リテラル
    • キーワードbreak, continue, fallthrough, またはreturnのいずれか
    • 演算子と句読点++, --, ), ], または}のいずれか
  2. 複雑な文を1行に収めることができるように、閉じ括弧")"または"}"の前ではセミコロンを省略できます。

慣用的な使い方を反映するため、このドキュメント内のコード例では、これらのルールを使用してセミコロンを省略しています。


解説

セミコロンとは何か?

セミコロン(;) は、プログラミング言語で「文の終わり」を示す記号です。C言語やJavaでは、すべての文の最後にセミコロンを書く必要がありますが、Goではほとんどの場合、セミコロンを省略できます

たとえ話: 日本語の文章で句点(。)を使うように、プログラミングでもセミコロンで文を区切ります。ただし、Goは賢いので「ここで文が終わるな」と自動的に判断してくれます。

package main

import "fmt"

func main() {
    // セミコロンなしで書ける(推奨)
    var x int = 10
    var y int = 20
    fmt.Println(x + y)
    
    // セミコロンを明示的に書いてもOK(非推奨)
    var a int = 10;
    var b int = 20;
    fmt.Println(a + b);
}

ルール1: セミコロンが自動挿入される場合

行の最後のトークンが以下のいずれかの場合、その行末に自動的にセミコロン;が挿入されます。

1-1. 識別子

package main

import "fmt"

func main() {
    var userName string
    // ↑ この行末に自動的に ; が挿入される
    
    userName = "太郎"
    // ↑ この行末にも ; が挿入される
    
    fmt.Println(userName)
    // ↑ この行末にも ; が挿入される
}

実際にコンパイラが見ているのは:

var userName string;
userName = "太郎";
fmt.Println(userName);

1-2. リテラル(整数、浮動小数点、虚数、ルーン、文字列)

package main

import "fmt"

func main() {
    var age int = 25
    // ↑ 最後が数値リテラル "25" → ; が挿入
    
    var name string = "太郎"
    // ↑ 最後が文字列リテラル "太郎" → ; が挿入
    
    var pi float64 = 3.14
    // ↑ 最後が浮動小数点リテラル "3.14" → ; が挿入
    
    var char rune = 'A'
    // ↑ 最後がルーンリテラル 'A' → ; が挿入
    
    fmt.Println(age, name, pi, char)
}

1-3. 特定のキーワード(break, continue, fallthrough, return)

これらのキーワードで行が終わる場合、セミコロンが自動挿入されます。

package main

import "fmt"

func getValue() int {
    return 42
    // ↑ "return" で終わるので ; が自動挿入
}

func main() {
    for i := 0; i < 10; i++ {
        if i == 5 {
            break
            // ↑ "break" で終わるので ; が自動挿入
        }
        if i%2 == 0 {
            continue
            // ↑ "continue" で終わるので ; が自動挿入
        }
        fmt.Println(i)
    }
}

注意点: returnの後に値を書く場合は同じ行に書く必要があります。

package main

// 正しい書き方
func add(a, b int) int {
    return a + b  // returnと値を同じ行に
}

// 間違った書き方
func subtract(a, b int) int {
    return        // ここで ; が自動挿入されてしまう!
        a - b     // この行は到達不能コードになる(エラー)
}

1-4. 特定の演算子と句読点(++, –, ), ], })

package main

import "fmt"

func main() {
    // インクリメント演算子 ++
    x := 10
    x++
    // ↑ "++" で終わるので ; が自動挿入
    
    // デクリメント演算子 --
    y := 20
    y--
    // ↑ "--" で終わるので ; が自動挿入
    
    // 閉じ括弧類
    numbers := []int{1, 2, 3}
    // ↑ "}" で終わるので ; が自動挿入
    
    result := getValue()
    // ↑ ")" で終わるので ; が自動挿入
    
    fmt.Println(x, y, numbers, result)
}

func getValue() int {
    return 100
}
// ↑ "}" で終わるので ; が自動挿入

これが最も重要な理由: 波括弧{}の位置に影響します。

package main

func main() {
    // 正しい書き方: 波括弧は同じ行に
    if true {
        // ...
    }
    
    // 間違った書き方: コンパイルエラー!
    if true
    {  // "true" で行が終わるので、前の行末に ; が自動挿入され、
       // "if true;" となってしまい、{ が単独で出現してエラー
        // ...
    }
}

正しい波括弧の書き方:

package main

import "fmt"

func main() {
    // if文: 波括弧は同じ行に
    if x := 10; x > 5 {
        fmt.Println("大きい")
    }
    
    // for文: 波括弧は同じ行に
    for i := 0; i < 10; i++ {
        fmt.Println(i)
    }
    
    // 関数定義: 波括弧は同じ行に
    myFunc := func() {
        fmt.Println("無名関数")
    }
    
    myFunc()
}

ルール2: 閉じ括弧の前ではセミコロンを省略できる

複雑な文を1行に書くとき、閉じ括弧)}直前ではセミコロンを省略できます。

複数の文を1行に書く場合

通常、複数の文を1行に書くにはセミコロンで区切る必要があります:

package main

import "fmt"

func main() {
    // 1行に複数の文を書く(非推奨だが可能)
    x := 10; y := 20; fmt.Println(x + y)
    
    // 閉じ括弧の前ならセミコロン省略可能
    if x := 10; x > 5 { fmt.Println("OK") }
    //                  ↑ "}" の前なのでセミコロン不要
}

スライスやマップの初期化

package main

import "fmt"

func main() {
    // 最後の要素の後のカンマ: あってもなくても良い
    numbers1 := []int{1, 2, 3}    // OK: カンマなし
    numbers2 := []int{1, 2, 3,}   // OK: カンマあり(推奨)
    
    // 複数行の場合
    numbers3 := []int{
        1,
        2,
        3,  // 最後のカンマを付ける(推奨)
    }  // "}" の前なのでセミコロン不要
    
    // カンマがないとエラー
    numbers4 := []int{
        1,
        2,
        3  // カンマがない!
    }  // エラー: "3" で行が終わるので ; が自動挿入され、
       // "3; }" となって構文エラー
    
    fmt.Println(numbers1, numbers2, numbers3)
}

推奨される書き方:

package main

func main() {
    // 複数行の場合は最後にカンマを付ける
    user := User{
        Name: "太郎",
        Age:  25,
        City: "東京",  // ← カンマを付ける
    }
    
    // 配列・スライス
    numbers := []int{
        1,
        2,
        3,  // ← カンマを付ける
    }
    
    // マップ
    prices := map[string]int{
        "りんご": 100,
        "バナナ": 80,
        "みかん": 60,  // ← カンマを付ける
    }
}

type User struct {
    Name string
    Age  int
    City string
}

慣用的なGoのスタイル

このドキュメントやGoの標準ライブラリのコード例では、セミコロンを省略しています。これがGoの慣用的なスタイルです。

package main

import "fmt"

// Goの標準的な書き方: セミコロンなし
func main() {
    name := "太郎"
    age := 25
    
    if age >= 20 {
        fmt.Printf("%sは成人です\n", name)
    } else {
        fmt.Printf("%sは未成年です\n", name)
    }
    
    for i := 0; i < 3; i++ {
        fmt.Println(i)
    }
}

// セミコロンを明示的に書く(非推奨)
func mainWithSemicolons() {
    name := "太郎";
    age := 25;
    
    if age >= 20 {
        fmt.Printf("%sは成人です\n", name);
    } else {
        fmt.Printf("%sは未成年です\n", name);
    };
    
    for i := 0; i < 3; i++ {
        fmt.Println(i);
    };
}

よくある間違いと対処法

間違い1: 波括弧を次の行に書く

package main

// ❌ 間違い
func main()
{  // エラー! ")" で行が終わるので ; が自動挿入
    // ...
}

// ✅ 正しい
func main() {
    // ...
}

間違い2: returnの後に改行を入れる

package main

// ❌ 間違い
func getValue() int {
    return  // ここで ; が自動挿入される!
        42  // 到達不能コード(エラー)
}

// ✅ 正しい
func getValue() int {
    return 42
}

// ✅ 長い式の場合は括弧で囲む
func getComplexValue() int {
    return (
        10 +
        20 +
        30
    )
}

間違い3: 複数行リテラルの最後にカンマを付けない

package main

// ❌ 間違い
func main() {
    numbers := []int{
        1,
        2,
        3  // カンマがない!
    }  // エラー!
}

// ✅ 正しい
func main() {
    numbers := []int{
        1,
        2,
        3,  // カンマを付ける
    }
}

セミコロンを明示的に書く場合

稀に、1行に複数の文を書きたい場合はセミコロンを使います(ただし非推奨):

package main

import "fmt"

func main() {
    // 1行に複数の文を書く(デバッグ時など)
    x := 10; fmt.Println(x)
    
    // for文の初期化、条件、後処理(これはOK)
    for i := 0; i < 3; i++ {
        fmt.Println(i)
    }
    
    // ifの短縮構文(これもOK)
    if x := getValue(); x > 5 {
        fmt.Println("大きい")
    }
}

func getValue() int {
    return 10
}

まとめ: セミコロンで覚えておくべきこと

  1. Goではセミコロンを省略できる(自動挿入される)
  2. 識別子、リテラル、特定のキーワード、特定の演算子で行が終わるとセミコロンが自動挿入される
  3. 波括弧{は同じ行に書く(次の行に書くとエラー)
  4. returnの後に値を書く場合は同じ行に(改行するとエラー)
  5. 複数行リテラルの最後の要素にカンマを付ける(セミコロン自動挿入対策)
  6. 閉じ括弧の前ではセミコロンを省略できる

実用的なアドバイス:

package main

import "fmt"

// ✅ 推奨される書き方
func main() {
    // 波括弧は同じ行
    if true {
        fmt.Println("OK")
    }
    
    // returnは同じ行
    result := func() int {
        return 42
    }
    
    // 複数行リテラルは最後にカンマ
    numbers := []int{
        1,
        2,
        3,  // ← カンマを忘れずに
    }
    
    fmt.Println(result(), numbers)
}

セミコロンの自動挿入ルールを理解すると、「なぜ波括弧を次の行に書けないのか」「なぜ最後にカンマが必要なのか」といった疑問が解消されます。Goらしいコードを書くための重要な知識です!

おわりに 

本日は、Go言語の言語仕様について解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました