這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
好多些天前,我在golang實踐群
裡問了下面代碼的問題:
package mainimport "fmt"type Aer interface{ Name()string PrintName()}type A struct {}func (a *A) Name() string { return "a"}func (a *A) PrintName() { fmt.Println(a.Name())}type B struct { A}func (b *B) Name() string { return "b"}func getAer() Aer { return &B{}}func main() { a := getAer() a.printName()}
這個實現中,golang輸出的是a,這個實現違反了通常C++,Java,Python中會輸出b的實現,由於上述幾個語言的思維習慣已經形成,那麼這個實現就會導致很多意想不到的事情。
昨兒個在golang實踐群
中,有贊的兄弟(這位兄弟知道我提的上面的問題,並說這個是golang的實現方式)就問到了,在UnmarshalJSON的時候,為何Test欄位沒有被賦值,並在golang中提了issue
他的代碼如下:
package mainimport ( "encoding/json" "fmt")type request struct { Operations map[string]op `json:"operations"`}type op struct { operation Test string `json:"test"`}type operation struct { Width int `json:"width"` Height int `json:"height"`}func (o *operation) UnmarshalJSON(b []byte) error { type xoperation operation xo := &xoperation{Width: 500, Height: 500} if err := json.Unmarshal(b, xo); err != nil { return err } *o = operation(*xo) return nil}func main() { jsonStr := `{ "operations": { "001": { "test":"test", "width": 100 } } }` req := request{} json.Unmarshal([]byte(jsonStr), &req) fmt.Println(req)}
這個問題的本質和我提出的那個問題一樣,因為op中嵌入了operation,所以有了UnmarshalJSON,符合了json包中Unmarshaler介面,所以內部用介面去處理的時候,op是滿足的,但實際處理的是operation,也就是以operation作為實體來進行UnmarshalJSON,導致了詭異的錯誤資訊。
我以為,這是golang實現中非常醜陋的一個地方。
按照耗子哥說的,如果語言實現規則是知道的,還是容易犯錯誤的,那就是一個坑。
這個golang的坑,估計以後還得填。