Edited at
GoDay 9

Golangのconst識別子iotaの紹介

More than 1 year has passed since last update.

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", three)
}

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", three)
}

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 // true
)

他の定義と混在しても、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