blank identifyで受けるテク
この記事はミクシィ20新卒 Advent Calender 2019 4日目の記事になります。
実は僕は19新卒なんですが、20新卒採用で内定をいただいているので「俺は20新卒やぞ」という強い意志でこの記事を書いています。
怒られたらやめますって書いてたんですけど、誰にも怒られなくてよかった。
特に良いテーマが思いつかなかったので、普通に Go の話を書きます。
Goでは、プログラム中に登場する"_"(アンダースコア1つ)の識別子を、blank identifyと呼ばれ、他の命名の識別子とは明確に区別されて処理されます。
ここしばらくGoを書いてきて、かなりトリッキーな使い方ができることが分かってきたので、その話です。
blank import
import文で別名をつけることができますが、そのときblank identifyで受けると、そのパッケージを未使用でもコンパイルエラーになりません。
一見未使用のパッケージを放置する使い道としては、使っていないパッケージを消すのをめんどくさいときに使うだけかと思いますが、importしておくと、そのパッケージ内のinit()を呼ぶことができるので、無意味ではありません。
database/sqlパッケージのドライバなんかは、よくblank importして使いますよね。
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
まあこれはもはやそういう文法なので、みんな知っているかと思います。
interfaceが実装されているか静的にチェックする
ここからは結構知らないんじゃないかと思います。
blank indetを使えば、ある型にinterfaceが実装されているかどうかを静的に確認することができます。
次のように、io.Readerを実装した構造体Hogeを考えてみます。
type Hoge struct{}
var _ = io.Reader(Hoge(nil))
func (Hoge) Read([]byte) (int, error) {
// 略
}
パッケージ変数にblank identifyを使い、Hogeをio.Readerでキャストしています。
こうしておくことで、もし構造体Hogeがio.Readerを実装していない場合は、io.Readerにキャストできないため、コンパイルエラーになります。
逆に実装していた場合は、コンパイルエラーにならないだけでなく、blank identifyは無意味なため最適化時に消去され、ビルド後のバイナリからは跡形もなく消え去るため、まったくオーバーヘッドが発生しません。
また、どのinterfaceが実装されているのかが明示できるため、可読性も上がります。
一石三鳥のお得なテクニックですね。
構造体の名前付き初期化強制化
これは、このテクニックの応用になります。
記事内では、構造体のフィールドに1つ非公開フィールドを作っておくことで、初期化時にフィールド名の指定を強制できるとして紹介しています。
ただ、そのままでは、Golandを使っている人は分かると思いますが、fill all fieldsすると、次のようなスニペットが展開されてしまいます。
type MustKey struct {
Name string
Second string
_hoge struct{}
}
func main() {
a := MustKey{
Name: "",
Second: "",
_hoge: struct{}{},
}
}
そこで、非公開フィールドの名前をblank identifyにしておくと、Golandでfill all fieldsを使っても、本当に必要なスニペットのみ展開されます。
type MustKey struct {
Name string
Second string
_ struct{}
}
func main() {
a := MustKey{
Name: "",
Second: "",
}
}
また、構造体のフィールドに[N]byte(byteのスライスではなく配列)のblank identifyを入れて、アライメント調整として使われることもあります。
配列の境界チェック削除
以前したこのツイートのテクニックです。
encoding/binaryを読んでたら変なテクを発見した
— しゅもん (@shumon_84) July 21, 2019
Go言語で、関数のはじめで関数内で使う最大の添字でアクセスしてblank indentifyで受けておくと、コンパイラが境界値チェックを省けるので高速になる
黒魔術的知見だ......https://t.co/8AuWBtvgHk pic.twitter.com/MTHQIQa1tj
ちなみに、計測していないので果たしてこれだけでどのくらい早くなるのかは知りません。
詳しくはBounds Check Eliminationとして、ここで紹介されています。
まとめ
blank identify使うとちょっとカッコいい書き方ができるので面白いですね。
実は以前、オシャレでカッコイイGolangテク 15選を書いたときにもblank identifyで受けるテクを一部紹介しているので、気になる人はそっちも見てください。
- 無名引数
- iota テク
とかがそうですね。
あと、20新卒のみんなえらいですね。
アドカレの埋まり具合を見てもらえると分かりますが、19新卒のアドカレはみんな最後の方とか土日とかに片寄っているんですけど、20新卒のアドカレはみんな先頭から埋めていたり1人で複数回登録していたり、主体性と協調性を兼ね備えた素晴らしい新卒ですね(なつよしは除く → リンク先が間違っていることを指摘してくれたのでなつよしは有能)