Go 很像加強版的 C,例如只要把 type 想像成 function call 的第一個參數,
那 method 就只是自動放參數而已。比如 POSIX C 裡頭的 time
:
1 |
|
對照 Go 的 time.Unix()
:
1 | func (t Time) Unix() int64 |
這樣就很明顯了。
會講到這個是因為這陣子碰到一個奇怪的 bug,相同的情況在 native 環境下
reflect.DeepEqual
是相等,而 Docker 環境下 DeepEqual 不相等。印 log
出來發現不相等原因是 struct 裡面 time.Time
這個 field 比出來不相等,
但用 %v
印出來卻是一樣的。參考 DeepEqual 的說明,推測應該是針對 Time
裡面的每個 field 用 ==
去比對,所以就改用 %#v
印,抓到是 loc
*Location
這欄位不一致,原因是 Docker 預設 timezone UTC,而我本機環境
是 CST。參考原始碼,time.Time
定義如下:
1 | type Time struct { |
sec
, nsec
這兩個欄位放的是 Epoch 絕對時間,而用 loc
放時區。所以
同樣的「時間點」,不同的「時區」時,會造成 struct 內容不一致,
DeepEqual 就認為不相等了。追到這裡覺得似乎很合理,就把兩邊的時間都轉換
成 func (Time) Local
再來比對,結果卻仍然不相等,而且 %#v
印出來
「每個欄位」的值,包括 *Location 的 pointer 指向位址都一樣,這樣還是不
相等,就很傻眼了。
要再知道原因當然有辦法,讀 DeepEqual 的原始碼就可以,但已經花了不少時間,
而且這方向感覺解法不漂亮。因為 reflect 相關函數的速度都會慢,已經看這個
DeepEqual 不爽很久了,就直接另外用 type switches 寫了針對不同型別的比對
方式,碰到 time.Time
就直接呼叫 func (Time) Equal
,把 DeepEqual 當
成最後手段來用。
然而這個疑惑還是沒完全解開,最近時間不夠用,只好先丟著以後再追。