2014年1月31日金曜日

Golang Cafe #14を開催しました。

Golang Cafe #14を開催しました。今回は、flagパッケージの使い方を見ていきました。
サンプルコードは少ないですが、githubにありますので、御覧ください。

ポイントを紹介すると、goでは、コマンド引数を受け取るためには、flag.Parse()を呼びださなければいけません。この時、引数の解析が行われます。
https://github.com/tyokoyama/golangcafe/blob/master/sample.com/flagsample/flagsample.go#L33

引数のリストをただ取得するだけなら、flag.Args()か、flag.Arg(i)
flag.Args()は[]stringに全ての引数が文字列として格納されます。ただし、オプションは含まれません。ということで、Goでは、オプションの解析はランタイム側でやってくれるというので便利に使えます。
https://github.com/tyokoyama/golangcafe/blob/master/sample.com/flagsample/flagsample.go#L37

オプションを指定する場合、例えば、flag.Bool(オプション名,既定値,ヘルプメッセージ)を呼び出し、受け入れるオプションを指定します。flag.Bool()だけでなく、flag.Int()や、flag.Float64()などもあります。
https://github.com/tyokoyama/golangcafe/blob/master/sample.com/flagsample/flagsample.go#L25

Durationを指定する場合は、"-time=1s"など、timeパッケージで指定するような文字列を指定することになります。
また、整数型などで、"-i 10"とすると、-iオプションに10を指定するという意味になりますが、"-i hoge"とやると、flag.Parse()の段階でエラー終了するので、指定方法は注意して下さい。

オプションの指定内容を任意の変数に渡す場合は、flag.BoolVar()を呼び出して下さい。
これもInt、Floatなど、同じようなメソッドはたくさんあります。
https://github.com/tyokoyama/golangcafe/blob/master/sample.com/flagsample/flagsample.go#L30

flag.PrintDefaults()を呼び出すと、ヘルプメッセージと既定値が出力されます。
コマンド引数が不正な時や、ヘルプ機能を実装する時に利用すると便利です。
https://github.com/tyokoyama/golangcafe/blob/master/sample.com/flagsample/flagsample.go#L41

最後に、オプション引数を全てチェックしたい場合には、flag.Visit()があります。flag.Visit()とflag.VisitAll()がありますが、Visit()の方は、指定されたもののみが、引数として呼び出され、VisitAll()は指定されていないものも全て引数に指定されて呼び出されます。
https://github.com/tyokoyama/golangcafe/blob/master/sample.com/flagsample/flagsample.go#L46

これで、flagパッケージの使い方は大体分かった…
のですが、「オプション引数の順番を解析する方法は?」という疑問が上がったので、
その時、「順番は解析できないだろう」と(C言語とかだと、引数が文字列として渡されるのでチェック可能だろうけど、力づくよね…)言っていたのですが、実際に動作している
godocコマンドや、goコマンドのソースコードを読み進めてみました。

私は、goコマンドしか読み進めなかったので、goコマンドの引数のチェックについて書き残しておきます。

goコマンドは例えば、
$ go test -v

という感じでコマンドを実行します。最初にflag.Parse()が実行されるので、全て文字列の引数として受け取ります。

ここで、goコマンドは賢く振舞っていました。flagパッケージには、FlagSet型のflagを再構築(?)する構造体があり、第1引数でサブコマンドに分類した後、第2引数以降を再度FlagSetを使って解析していました。
http://golang.org/pkg/flag/#FlagSet

と言ったところで、今回は終了しました。
goコマンドで使えないオプションを指定した時に、エラーにしている所があったので、探していたのですが、結局見つけられず…。flagパッケージのソースコードに埋め込まれたメッセージが表示されていたので、どこかでParse()しているはずなんですが…。

ということで、goコマンド自体は、かなり読みやすいコードだと思いました。コマンドの分類もしてありますし、構成もシンプルでわかりやすいものでしたので、一度、読んでみるのもいいのではないでしょうか。

次回は、netパッケージになります。