2013-05-10

Go で関数に型っぽく渡す

先日、Go の型は First-class ではないことを、ぐずぐず書いていたら、こんなコメントがありました。

もともと困っていたのは、型を引数にできないことでした。そして、見たところ Go は型(int とか、type Foo struct{...} の Foo とか)を引数にできません。できないのですが、やりたいことは「型をわたすこと」ではありません。

やりたいことは、「クエリ対象の指定をもうちょい安全にしたい」です。NewQuery(c, "Foo") だと "Eoo" と書いて渡してもコンパイルを通ってしまい実行時にエラーになるけれど、すでに定義してある Foo 型を使うのだ、と記述することができれば少しは安全側に倒れるのではないか、と考えたわけです。その仮定で、型を知らせるために、使いもしない変数を定義することに居心地の悪さを感じていました。

そこで @mattn さんの &Foo{} という書き方ですよ。f(&Foo{}) や f(Foo{}) と書けば型を知らせているのだ、と分かりやすいし、余計な変数宣言もないしで、なかなかいい。たぶん Foo 型の値が生成されそうで、要らないメモリだろうと思ったりもしましたが、自分が書くコードではもっと別なボトルネックがありそうです。そんなわけで、この書き方いいなぁと思っています。

あとですね。そもそも型を渡して〜というアプローチが、 Go の考え方に合っていない気がしています。先日のブログにも書いたのですが、ここではクエリを発行して、そのあとデータストアから Foo の配列に値を取ってくるわけです。非同期に実行するとしても chan を使うでしょう。なので Foo の型情報を持った変数が、文脈上あとで必ず出てきます。であれば、ここからここまでで Foo 配列に対する操作をしまっせー、という中にクエリ発行が出現する、という書き方もできて、それが合っている気もしてきました。