ゼロから学ぶGo言語プログラミング(9) A Tour of Go 34~39
A Tour of Goの続き。 rangeとmap。
34.Range
これもpythonっぽいrange機能。 mapはまだツアーに登場してないけど、辞書みたいなものかな。
for i, v := range foo { }
これでfooが持つインデックスがiに、値がvに渡される。
ただ、"range フォーム"という表現が引っかかる。 翻訳の揺れなどではなく、元の英文でも"range form"となってる。
35.Range continued
インデックスや値を " _ "(アンダーバー) へ代入することで破棄することができます。
破棄することで、受け取って使わないよりも不要なリソースを確保せず済むんでしょうか。
for _, _ := range foo { }
こうすると、fooの長さ分処理ができると思ったら、":="での型推論がひっかかった。 コロンを外せば動いたので、アンダースコアも減らす。
for _ = range foo { }
さてこれが、len()でカウント取ってのループとどっちが効率良いのか。 range使った方が好みだけど、"_"を省略できないのはちょっと残念。
36.Exercise: Slices
バイト列を使った画像の生成の課題。 色々わかりにくい。
まず、"code.google.com/p/go-tour/pic"からのimport。 恐らく受け取ったバイト列を画像として出力するためのパッケージ。 pic.show()がそれに当たるらしい。
pic.show()はPic関数を引数として受け取るようだけど、課題の開始時点でPicには引数がない。 と思ったら、pic.show()にはPicを関数として渡していた。 つまり、pic.show()側で渡されたPicに、生成するサイズとなるdxやdyが渡されるということらしい。
次に分からないのが、"uint8"というPicの戻り値の指定。 まだまだ目がなれないので一見でわからないけれど、sliceはの後に、そのsliceが保持する中身の指定を行うようなので、Picの戻り値はuint8が連なったslice、ということになるようだ。 と思ったのだけど、それだとsliceを用意するmakeの書き方がわからない。 結局試行錯誤して、コードは次のようになった。
package main import "code.google.com/p/go-tour/pic" func Pic(dx, dy int) [][]uint8 { ret := make([][]uint8, dx, dy) for i := 0; i < dy; i++ { row := make([]uint8, dx) for k := 0; k < dx; k++ { row[k] = uint8(i ^ k) } ret[i] = row } return ret } func main() { pic.Show(Pic) }
"uint8"のように、""を連ねると、多次元のsliceを示すようで、make()での長さ指定は引数を増やして対応するらしい。 多次元配列を"[]uint8"という風に初期化しないといけないのは、動的に次元の増減は難しいということだろうか。
ついでに、呼び出しているpic.Show()のコードも見てみました。
やはり、int2つを引数に取る関数がShow()の引数でしたが、引数として関数を与える場合、
func Show(f func(int, int) [][]uint8) { }
というように、引数の場所に関数名、引数となる関数の引数、そして引数となる関数の戻り値まで記述するようです。 こういう風に関数を引数に取れるのは、Goがモダンなところなんでしょうか。
Sho()の結果は、imageパッケージを使ってRGBA画像としておき、それを更にShowImage()でbase64として返しています。 最終的な出力時に"IMAGE:"という文字列を先頭に付加していますが、これはplaygroundが画像としてbase64のデータを出力するためのフラグのようです。
sliceによる多次元配列の扱いは、まだ全然慣れませんが、使いこなせると強力そうです。
37.Maps
mapはやはり辞書のようです。
mapの初期化はsliceと同じmake()で、キーへのアクセスは"m["キー"]"です。 mapもsliceと同じく、保持する値の型を、make時に指定する必要があるようです。
38.Map literals
リテラルとしてのmapは"キー: 値"というペアでダイレクトに指定でき、make()で準備する必要がないようです。 stringのmapであれば、こんな風に定義できました。
var m2 = map[string]string{ "a": "b", "c": "d", "e": "f", }
39.Map literals continued
これ、38で試したコードではすでにstringを個々のmap要素に書いてませんが、Vertexの場合と同じように考えていいんでしょうか。
"トップレベル"とは、Vertexがmainパッケージの直下に指定されている事と同義と捉えていいのかどうか…。