katsuの駄日記

stringer @ Go

Goにもenumがあるような感じで書かれてる記事もあるようですが、 実際にはC言語のようなenumはサポートされてないんですね。 かわりに、iotaという特殊な変数を使うのだとか。

Go言語では、enumをサポートしていません。その代わりに、特殊な名前iotaを使って、ひとつのconst宣言内で、連続して増加する値を得ることができます。const内で、初期化式が省略されたときは、前の式が再利用されます。

http://golang.jp/go_for_cpp_programmers

関数の引数のチェックには有用なんですけどね、enum。 まぁ、C言語だと中身は整数値だと定義されちゃってるという不幸な仕様なためキャスト可能なので、 何も考えてない人が使うと不幸しか起こらないんですけどね。 しかも、コンパイラによって何バイトの整数使うか変わってくるんですよね……。 死ねます。

まぁそれはさておき、C言語のenumでも、デバッグのログ表示に四苦八苦するんですが、 goにはstringerなるものがあるらしい。 情報元は、例によってQiita(のコメント)。

constのString()を自動生成するstringerというツールが公式でサポートされてますよ

http://qiita.com/ksato9700/items/6228d4eb6d5b282f82f6#comment-371a5768589b45b45a2e

こちらのページ が大いに参考になりますし、 godocのページ もありまっせ。

使い方ですが、まずは go get が必要みたいです。 階層が深いので若干面倒……。

$ go get golang.org/x/tools/cmd/stringer

次に、以下のようなコードを準備しました。

package main

import "fmt"

//go:generate stringer -type hoge
type hoge int

const (
    Alice hoge = iota
    Bob
    Carol
    Dave
    Eve
    Frank
    Godzilla
)

func main() {

    var test hoge

    for test = Alice; test <= Godzilla; test++ {
        fmt.Println(test)
    }
}

なんか、整数型のtypeじゃないと駄目みたいなので hoge とかいう型つくってます。 その時点で既に違和感ありますが……まぁ、そのあたりは感じないフリをして。

この、コメントにある go:generate stringer -type hoge というのがミソで、 こちらを指定したあとに

$ go generate

とすると、以下のようなコード (hoge_string.go) を生成してくれました。

// Code generated by "stringer -type hoge"; DO NOT EDIT

package main

import "fmt"

const _hoge_name = "AliceBobCarolDaveEveFrankGodzilla"

var _hoge_index = [...]uint8{0, 5, 8, 13, 17, 20, 25, 33}

func (i hoge) String() string {
        if i < 0 || i >= hoge(len(_hoge_index)-1) {
                return fmt.Sprintf("hoge(%d)", i)
        }
        return _hoge_name[_hoge_index[i]:_hoge_index[i+1]]
}

ちなみに、 // の後にスペースを入れたら認識してくれず、コード生成してくれませんでした。 まじかよぉ……ぅ.

そのあと、 go generatego build を実行して stringer を実行すると、

$ ./stringer
Alice
Bob
Carol
Dave
Eve
Frank
Godzilla

と期待した通りの挙動をしてくれました。

いやぁ、これは便利…………かなぁ? まぁ、もちろんログ吐くときは便利だけど、 こんなツールとして対応するより、ちゃんとenum作ってくれてコンパイル時にエラー吐いてくれて、 printlnに渡したら文字列表示してくれた方が幸せなのだが……。

まぁ、静的に解析するのは難しいか……。 テストも書くのも難しくなりそうだし…………うーん。

misc Go