Go言語の識別子iotaについて

Go言語の標準パッケージtimeにおいて、以下の定数定義があります。

type Month int

const (
    January Month = 1 + iota
    February
    March
    April
    May
    June
    July
    August
    September
    October
    November
    December
)

各月に対応する数値を定義した定数であり、それぞれの評価値は(皆様の推測の通り)以下の通りとなります。

package main

import ( 
    "fmt"
    "time"
)

func main() {
    fmt.Printf("%d\n", time.January)   //-> 1
    fmt.Printf("%d\n", time.February)  //-> 2
    fmt.Printf("%d\n", time.March)     //-> 3
    fmt.Printf("%d\n", time.April)     //-> 4
    fmt.Printf("%d\n", time.May)       //-> 5
    fmt.Printf("%d\n", time.June)      //-> 6
    fmt.Printf("%d\n", time.July)      //-> 7
    fmt.Printf("%d\n", time.August)    //-> 8
    fmt.Printf("%d\n", time.September) //-> 9
    fmt.Printf("%d\n", time.October)   //-> 10
    fmt.Printf("%d\n", time.November)  //-> 11
    fmt.Printf("%d\n", time.December)  //-> 12
}

前述の定数定義で使用されている識別子iotaについて、仕様書を見て調べてみました。

識別子iotaは、定数宣言文(const)内で使用される、連続する型未定の整数の定数を表します。この定数は予約語constが現れたときに0に初期化され、各定数定義の後に1ずつインクリメントされます。

package main

import (
    "fmt"
)

const (
    a0 = iota // 予約語constがあるため0に初期化される
    a1 = iota // 1
    a2 = iota // 2
)

const (
    b0 = iota // 予約語constがあるため0に初期化される
    b1 = iota // 1
    b2 = iota // 2
)

func main() {
    fmt.Println(a0) //-> 0
    fmt.Println(a1) //-> 1
    fmt.Println(a2) //-> 2

    fmt.Println(b0) //-> 0
    fmt.Println(b1) //-> 1
    fmt.Println(b2) //-> 2
}

iotaの値を用いた演算結果を定数に設定することもできます。

package main

import (
    "fmt"
)

const (
    a0 = iota      // 予約語constがあるため0に初期化される
    a1 = iota * 10 // 1 * 10
    a2 = iota * 20 // 2 * 20
)

func main() {
    fmt.Println(a0) //-> 0
    fmt.Println(a1) //-> 10
    fmt.Println(a2) //-> 40
}

また、定数宣言文内で代入値を省略すると前回の代入と同じ値が代入されるため、これを利用してiotaの記載を省略しながら、連続した値を定数として定義することができます。

package main

import (
    "fmt"
)

const (
    a0 = iota // 予約語constがあるため0に初期化される
    a1        // 前回と同じくiotaが代入されるため、1が代入される
    a2        // 前回と同じくiotaが代入されるため、2が代入される
    a3 = 10
    a4        // 前回と同じく10が代入される
    a5 = iota // 5(a3、a4の定数定義でiotaが使用されていなくとも、iotaはインクリメントされている)
    a6        // 前回と同じくiotaが代入されるため、6が代入される
)

func main() {
    fmt.Println(a0) //-> 0
    fmt.Println(a1) //-> 1
    fmt.Println(a2) //-> 2
    fmt.Println(a3) //-> 10
    fmt.Println(a4) //-> 10
    fmt.Println(a5) //-> 5
    fmt.Println(a6) //-> 6
}

以上のように、識別子iotaを用いることで、連続した値を持つ定数を簡潔に定義することができるようになります。

*本記事は、執筆時点におけるGo言語の最新バージョンである1.2の仕様ソースコードに基づいて執筆されています。