嫌だなぁと感じる場面
業務を進める中で、以下の様なコードを書くことが多かった。
drink := "" if orderNum { drink = "green tea" } else { drink = "tea" }
orderNum
の様な関数の引数で指定される値であったり、http
経由で指定されたquery
によって値をセットする処理なのだが、事前にdrink
という同じ型に該当する初期値となる変数を用意しておく必要があり個人的には好きではない。しかしながら、これがgolang
の言語デザインでもあり、Qiita
でRui Ueyamaさんも言及している。
「三項演算子があればなぁ...」と思い、何とかならないかなとあがいた結果が以下になる
無名関数を使った記述方法
先ほどのコードを無名関数を使った三項演算子っぽいものに書き換えてみた。
func Sample(orderNum int) string { // 無名関数を即時実行する drink := func(n int) string { if n == 1 { return "green tea" } else { return "tea" } // 即時実行のために引数を指定 }(orderNum) // 無名関数の実行結果を返す return drink }
やっていることは大したことはなくて、無名関数を定義して、その無名関数の戻り値を任意の変数に代入にしているだけ。わざわざ、外部に関数を定義するまでもないので無名関数で良くないかという判断に至った。n
の値によって戻り値のパターンを増やしたいのならswitch
文の採用も考える。無駄な変数を宣言する必要がないため、割と気に入っている。
パフォーマンスについて
気になるのは、無名関数を使った記述方法にすることで、どれだけオーバーヘッドになってしまうのかという点。普通に考えて、無名関数を使った方がパフォーマンスは悪いだろうなと思うが、考えても分からないので測定してみた。
それぞれ無名関数を使用する記述と、従来の記述とで1万回ずつ測定して、平均値を算出した。
比較のためにそれぞれを関数内に内包して、それぞれの関数の実行速度を比較するとする。
func AnonymousFunctionSample(orderNum int) string { // 無名関数を即時実行する drink := func(n int) string { if n == 1 { return "green tea" } else { return "tea" } // 即時実行のために引数を指定 }(orderNum) // 無名関数の実行結果を返す return drink } func NormalSample(orderNum int) string { drink := "" if orderNum == 1 { drink = "green tes" } else { return "tea" } return drink }
検証に使用したコードはこちら。
github.com
実行結果
$ bash benchmark.sh
[info] clear go test cached... [info] start benchmark === RUN TestSample [info] average for anonymous function: 9.854730000000441e-08 [info] average for normal exec: 1.0573470000000177e-07 --- PASS: TestSample (0.01s) PASS ok ternary_operator/src 0.015s
1万回平均で見ると、無名関数を使用した記述方法の方が速いようだ。
可読性は好き嫌いが分かれる所だと思うが、良ければ使ってください。