有名な話です。が、いざ自分が体験したので備忘録としてまとめます。
上記で上げられている netcontextとcontext周りで死ぬ
というのに引っかかりました。
課題
go1.6上で以下のようなリクエスト比較するコードを書いてました。 ※ コードはあくまでサンプルです。
url := "https://www.gooogle.com" values := url.Values{} req_1, _ := http.NewRequest("POST", url, strings.NewReader(values.Encode())) req_2, _ := http.NewRequest("POST", url, strings.NewReader(values.Encode())) if reflect.DeepEqual(req_1, req_2) { // requestが同値である。 } else { // requestは同値でない }
req_1
と req_2
をdeepEqualで比較して、同値性を判別したいという意図でしたが、このコードはgo1.6だと同値だと判定されますが、go1.8だと同値だと判定されません。
理由は最初に書いた netcontextとcontext周りで死ぬ
が原因だと思われます。
goのx/net/context パッケージが標準の context に入ったというのは有名です。
refs: Go 1.7 Release Notes - The Go Programming Language
net/context も標準のcontextとして扱われるようになったので、req_1
と req_2
は別々のリクエスト、すなわち異なるcontextを持っていると判定され、それを reflect.DeepEqual
にかけた場合、標準の context 違いがあるので、同値判定されません。
go1.7のcontextについては以下のブログがすごく勉強になりました。
同値性の比較
では、requestの比較をしたい場合はどうすればいいかというと、 httputil.DumpRequest
を使います。
refs: httputil - The Go Programming Language
url := "https://www.gooogle.com" values := url.Values{} req_1, _ := http.NewRequest("POST", url, strings.NewReader(values.Encode())) req_2, _ := http.NewRequest("POST", url, strings.NewReader(values.Encode())) // dumpは[]byte型 dump_1, _ := httputil.DumpRequest(req_1, true) dump_2, _ := httputil.DumpRequest(req_2, true) // DeepEqual if reflect.DeepEqual(dump_1, dump_2){ // requestの同値判定 } // bytes.Equal if bytes.Equal(dump_1, dump_2) { // requestの同値判定 } // stringに変換して文字列比較 if string(dump_1) == string(dump_2) { // requestの同値判定 }
DumpRequest
することで context ではなくリクエストそのものを比較出来ます。
比較方法は、以前同様 DeepEqual
を使ってもいいですし、 []byte
型に変換されるので、それに合わせて bytes
packageを使ってもいいですし、文字列に変換して文字列一致をしても同値性を取ることが出来ると思います。