Golangのconst識別子iotaの紹介

  • 24
    いいね
  • 0
    コメント

Go AdventCalendar2016の9日目(2016/12/09)の記事です。
前の記事は massa142さんの「Hacker Newsを一覧表示してくれるCLIツールを書いた」でした。

はじめに

ちょっとマイナーなGolangの言語仕様である、iotaについて紹介します。
結構入門書とかにも書いてあるんですが、読み飛ばしがちなんですよね。
特に新規性がある内容ではないので、タイトルでもう知ってるわ!という方はそっ閉じしてもらって大丈夫です。

iotaとは

iotaは、定数宣言(const)の内での既定された識別子です。
型なしの整数の連番を生成します。具体例を見ましょう。

package main

import "fmt"

const (
    zero  = iota
    one   = iota
    two   = iota
    three = iota
)

func main() {
    fmt.Printf("zero:%v\n", zero)
    fmt.Printf("one:%v\n", one)
    fmt.Printf("two:%v\n", two)
    fmt.Printf("three:%v\n", two)
}

https://play.golang.org/p/9uycXahdRE
結果はこうです。

zero:0
one:1
two:2
three:3

最初の1つのみ設定しておけば、あとは省略することが可能です。
(ちなみにこれはiotaに限らず、定義する値を省略すると、直前に定義されたものが流用されます。)

package main

import "fmt"

const (
    zero  = iota
    one
    two
    three
)

func main() {
    fmt.Printf("zero:%v\n", zero)
    fmt.Printf("one:%v\n", one)
    fmt.Printf("two:%v\n", two)
    fmt.Printf("three:%v\n", two)
}

https://play.golang.org/p/IFkQnrwujr

ConstSpec毎にインクリメントされ、次の予約語constが現れたらリセットされます。

const (
    zero = iota // 0
    one  = iota // 1
)
const (
    two   = iota // 0
    three = iota // 1
)

また、constの中であれば、式のなかで利用することもできます。

const (
    zero  = iota * iota // 0
    one                 // 1
    two                 // 4
    three               // 9
)
const (
    zero  = iota != 1 // true
    one               // false
    two               // true
    three             //false
)

他の定義と混在しても、ConstSpecのたびにインクリメントしています。

const (
    zero  = "zero" // zero
    one   = iota   // 1
    two   = "弐"    // 弐
    three = iota   // 3
)

また、const内で先にiotaを設定すると結構面白かったです。iotaの機能ではなく、定数が優先されました。

const (
    iota  = "iota" // iota
    zero  = iota   // iota
    one            // iota
    two            // iota
    three          // iota
)

型なしの整数なのでconstで使用した定数をTypeOfするとintになります。

package main

import (
    "fmt"
    "reflect"
)

const (
    zero = iota
)

func main() {
    fmt.Printf("zero type:%v\n", reflect.TypeOf(zero))
}

https://play.golang.org/p/851VyBBlgs

ですので、このような定義をすると変換できないのでコンパイルエラーとなります。

const(
    zero string = iota
)

.../main.go:6: cannot convert 0 to type string

Githubではこういう感じで使われてたよ

軽く見た感じ単純にフラグ的なものをconstするソースが殆どだったんですが、

type ByteSize float64

const (
    _           = iota // ignore first value by assigning to blank identifier
    KB ByteSize = 1 << (10 * iota)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)

https://github.com/golang/go/blob/964639cc338db650ccadeafb7424bc8ebb2c0f6c/doc/progs/eff_bytesize.go
このソースはシフト演算子でByteSize型の値作ってて面白かったです。

おわりに

というわけで、iota列挙子のご紹介でした。

ひらめき次第で楽しく使えそうなので、こういうとこで使うと便利、こういう感じで使ってるとこあった、などあったら教えていただけるとうれしいです。

参考文献

Iota · golang/go Wiki
https://github.com/golang/go/wiki/Iota

The Go Programming Language Specification - Iota
https://golang.org/ref/spec#Iota

Yosssi's blog - Go言語の識別子iotaについて
http://yosssi.hatenablog.com/entry/2014/01/27/000135

Big Sky:: Recent entries from same category
http://mattn.kaoriya.net/software/lang/go/20141208093852.htm