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

スポンサーリンク
Go言語入門:言語仕様 -Vol.7- 用語解説
Go言語入門:言語仕様 -Vol.7-
この記事は約13分で読めます。
よっしー
よっしー

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

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

スポンサーリンク

背景

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

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

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

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

Tokens(トークン)

トークンはGo言語の語彙を形成します。トークンには4つのクラスがあります。識別子、キーワード、演算子と句読点、そしてリテラルです。空白文字は、スペース(U+0020)、水平タブ(U+0009)、キャリッジリターン(U+000D)、改行(U+000A)から形成されますが、1つのトークンに結合してしまうトークンを分離する場合を除いて無視されます。また、改行またはファイルの終端はセミコロンの挿入をトリガーする場合があります。入力をトークンに分割する際、次のトークンは有効なトークンを形成する最も長い文字列になります。


解説

トークンとは何か?

トークンは、プログラミング言語における「最小の意味を持つ単位」です。日本語で言えば「単語」に相当します。

たとえ話: 日本語の文章「私は学校に行く」を分解すると、「私」「は」「学校」「に」「行く」という単語(トークン)になります。同じように、Goのプログラムもトークンに分解されます。

package main

func main() {
    var age int = 25
}

この短いプログラムを分解すると、以下のようなトークンになります:

  • package (キーワード)
  • main (識別子)
  • func (キーワード)
  • main (識別子)
  • ( (句読点)
  • ) (句読点)
  • { (句読点)
  • var (キーワード)
  • age (識別子)
  • int (識別子/型名)
  • = (演算子)
  • 25 (リテラル)
  • } (句読点)

トークンの4つのクラス

1. Identifiers(識別子)

識別子は、変数名、関数名、型名など、プログラマーが自由に命名できる名前です。

package main

import "fmt"

func main() {
    // すべて識別子
    var userName string = "太郎"
    var age int = 25
    
    calculateTotal(100, 200)
    
    fmt.Println(userName, age)
}

// calculateTotal も識別子
func calculateTotal(a, b int) int {
    return a + b
}

識別子の例:

  • 変数名: userName, age, count
  • 関数名: main, calculateTotal, Println
  • 型名: string, int, User
  • パッケージ名: main, fmt, net

2. Keywords(キーワード)

キーワードは、Go言語であらかじめ予約されている特別な単語です。これらは特定の意味を持ち、識別子として使うことはできません。

Goには25個のキーワードがあります:

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

使用例:

package main

import "fmt"

func main() {
    // if, else, for などはすべてキーワード
    for i := 0; i < 10; i++ {
        if i%2 == 0 {
            fmt.Println(i)
        } else {
            continue
        }
    }
}

注意: キーワードは識別子として使えません:

// これらはエラー!
// var if int = 10      // "if" はキーワード
// var func string      // "func" はキーワード
// var package float64  // "package" はキーワード

// 正しい例:
var myIf int = 10      // OK
var myFunc string      // OK

たとえ話: キーワードは、国語の授業で習う「てにをは」のような文法的に決まった役割を持つ言葉です。自由に使える普通の名詞(識別子)とは区別されます。

3. Operators and punctuation(演算子と句読点)

演算子は、計算や比較などの操作を行う記号です。句読点は、文の構造を示す記号です。

演算子の例:

package main

func main() {
    // 算術演算子
    a := 10 + 5   // + (加算)
    b := 10 - 5   // - (減算)
    c := 10 * 5   // * (乗算)
    d := 10 / 5   // / (除算)
    e := 10 % 3   // % (剰余)
    
    // 比較演算子
    x := 10 == 5  // == (等しい)
    y := 10 != 5  // != (等しくない)
    z := 10 > 5   // > (より大きい)
    
    // 論理演算子
    result := true && false  // && (論理積)
    result2 := true || false // || (論理和)
    
    // 代入演算子
    n := 10
    n += 5   // += (加算代入)
    n -= 3   // -= (減算代入)
}

句読点の例:

package main

func main() {
    // 括弧類
    (...)   // 丸括弧: 関数呼び出し、グループ化
    {...}   // 波括弧: ブロック
    [...]   // 角括弧: 配列、スライスのインデックス
    
    // 区切り文字
    ,       // カンマ: 要素の区切り
    ;       // セミコロン: 文の終わり(通常は省略可)
    .       // ドット: パッケージ・構造体のメンバーアクセス
    :       // コロン: ラベル、短縮変数宣言
}

実例:

package main

import "fmt"

func main() {
    // 括弧と区切り文字の使用例
    numbers := []int{1, 2, 3, 4, 5}  // {}, [], ,
    
    for i, n := range numbers {      // (), :, 
        fmt.Printf("numbers[%d] = %d\n", i, n)  // (), [], ,
    }
}

4. Literals(リテラル)

リテラルは、値そのものを直接表現したものです。数値、文字列、真偽値などが含まれます。

package main

import "fmt"

func main() {
    // 整数リテラル
    var decimal int = 42        // 10進数
    var binary int = 0b1010     // 2進数
    var octal int = 0o52        // 8進数
    var hex int = 0x2A          // 16進数
    
    // 浮動小数点リテラル
    var pi float64 = 3.14159
    var scientific float64 = 1.23e5  // 1.23 × 10^5 = 123000
    
    // 文字列リテラル
    var name string = "太郎"
    var message string = `複数行の
文字列も
書けます`
    
    // ルーンリテラル(文字)
    var char rune = 'A'
    var kanji rune = '漢'
    
    // 真偽値リテラル
    var isTrue bool = true
    var isFalse bool = false
    
    fmt.Println(decimal, binary, octal, hex)
    fmt.Println(pi, scientific)
    fmt.Println(name, message)
    fmt.Println(char, kanji)
    fmt.Println(isTrue, isFalse)
}

たとえ話: リテラルは、レシピに書かれた具体的な分量のようなものです。「砂糖大さじ2杯」の「2」がリテラルです。

空白文字(White space)の扱い

Goでは、以下の4種類の文字が空白文字として扱われます:

  • スペース(U+0020):
  • 水平タブ(U+0009): \t
  • キャリッジリターン(U+000D): \r
  • 改行(U+000A): \n

空白文字は基本的に無視される

package main

func main() {
    // これらはすべて同じ意味
    var x int = 10
    var    x    int    =    10
    var	x	int	=	10  // タブで区切っても同じ
}

空白文字は、トークン同士を区切るために使われますが、余分な空白は無視されます。

トークンを分離するために必要な空白

package main

func main() {
    // 空白が必要な例
    var x int = 10  // "var" と "x" の間にスペースが必要
    // varx int = 10  // エラー! "varx" という1つの識別子になってしまう
    
    // 空白が不要な例
    x:=10           // := の前後にスペースは不要
    x := 10         // あっても問題ない(可読性のため推奨)
    
    numbers:=[]int{1,2,3}     // 空白なしでも動作
    numbers := []int{1, 2, 3} // 空白ありの方が読みやすい
}

たとえ話: 日本語の「私は学校に行く」という文で、「私は」と「学校に」の間にどれだけスペースを入れても意味は変わりませんが、「私」「は」を「私は」と書くために文字をくっつける必要があります。同じように、トークンを区切るための最低限の空白は必要です。

改行とセミコロンの自動挿入

Goには重要な特徴があります。行末に自動的にセミコロンが挿入される場合があります。

セミコロンの自動挿入ルール

以下のトークンで行が終わる場合、自動的にセミコロン;が挿入されます:

  • 識別子
  • 整数、浮動小数点、虚数、ルーン、文字列のリテラル
  • キーワード: break, continue, fallthrough, return
  • 演算子と句読点: ++, --, ), ], }
package main

import "fmt"

func main() {
    // セミコロンは省略できる(自動挿入される)
    var x int = 10  // ← ここに ; が自動挿入
    var y int = 20  // ← ここに ; が自動挿入
    
    // 明示的にセミコロンを書いてもOK(非推奨)
    var z int = 30;
    
    fmt.Println(x, y, z)  // ← ここに ; が自動挿入
}  // ← ここに ; が自動挿入

自動挿入による注意点

package main

func main() {
    // 正しい書き方
    x := []int{
        1,
        2,
        3,  // 最後のカンマを付ける(推奨)
    }
    
    // 間違った書き方
    y := []int{
        1,
        2,
        3  // カンマがないと次の行の } でエラーになる
    }  // エラー: セミコロンが自動挿入されて構文エラー
    
    // 波括弧の位置に注意
    // 正しい
    if x > 0 {
        // ...
    }
    
    // 間違い!
    if x > 0
    {  // エラー! "if x > 0;" と解釈される
        // ...
    }
}

たとえ話: Goのコンパイラは、「この行はここで文が終わったな」と判断すると、自動的にセミコロンを補ってくれる親切な校正者のようなものです。ただし、改行位置を間違えると意図しない場所にセミコロンが入ってしまうので注意が必要です。

最長一致の原則(Longest match)

トークンを認識するとき、できるだけ長い文字列を1つのトークンとして扱います。

package main

func main() {
    // "++" は1つのトークン(インクリメント演算子)
    x := 10
    x++  // "+" と "+" ではなく、"++" として認識される
    
    // "==" は1つのトークン(等価演算子)
    if x == 11 {  // "=" と "=" ではなく、"==" として認識される
        // ...
    }
    
    // ":=" は1つのトークン(短縮変数宣言)
    y := 20  // ":" と "=" ではなく、":=" として認識される
}

具体例で理解する:

// これを見てみましょう
x:=10

// これは次のように分解されます:
// "x" (識別子)
// ":=" (演算子)
// "10" (リテラル)

// もし最長一致がなければ:
// "x" ":" "=" "10" と4つのトークンになってしまう

実用上の影響:

package main

func main() {
    // 空白を入れないと意図しないトークンになることがある
    x := 10
    y := x+++5  // これは "x++" と "+5" に分解される
                // つまり "x++; +5" という意味
    
    // 意図した動作にするには:
    y := x + (+5)  // または
    y := x + 5     // こう書く
    
    // 別の例
    a := 10
    b := 20
    c := a/* コメント */+b  // "a" "/* ... */" "+" "b" と分解
                             // コメントはスペースになるので問題ない
}

まとめ: トークンで覚えておくべきこと

  1. トークンは4種類: 識別子、キーワード、演算子と句読点、リテラル
  2. 空白文字は基本的に無視されるが、トークンを区切るために必要
  3. 改行でセミコロンが自動挿入される場合がある
  4. 最長一致の原則: できるだけ長い文字列を1つのトークンとして認識
  5. キーワードは予約語なので識別子として使えない

実用的なアドバイス:

package main

import "fmt"

func main() {
    // 読みやすいコードのために適切な空白を使う
    // 悪い例
    x:=10+20*30
    
    // 良い例
    x := 10 + 20*30  // 演算子の前後にスペース
    
    // 波括弧は同じ行に
    if x > 0 {       // OK
        // ...
    }
    
    // 改行位置に注意
    numbers := []int{
        1,
        2,
        3,  // 最後のカンマを付ける習慣を
    }
    
    fmt.Println(x, numbers)
}

トークンの理解は、Goの文法を正しく理解するための基礎です。特にセミコロンの自動挿入波括弧の位置は、初心者がつまずきやすいポイントなので注意しましょう!

おわりに 

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

よっしー
よっしー

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

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

コメント

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