2015-08-28 203 views
1

我對以下代碼的行爲感到困惑。 playground指針接收器混淆

var foo json.RawMessage 
_ = json.Unmarshal([]byte(`{ "zoo": 123 }`), &foo) 

enc := json.NewEncoder(os.Stdout) 

// Works as expected 
_ = enc.Encode(struct{ Foo *json.RawMessage }{&foo}) 

// MarshalJSON has a pointer reciever, so it doesn't get invoked here 
_ = enc.Encode(struct{ Foo json.RawMessage }{foo}) 

// How is MarshalJSON being invoked if .Foo is not a pointer? 
_ = enc.Encode(&struct{ Foo json.RawMessage }{foo}) 

輸出:

{"Foo":{"zoo":123}} 
{"Foo":"eyAiem9vIjogMTIzIH0="} 
{"Foo":{"zoo":123}} 

我不明白爲什麼要json.Encoder.Encode第三次調用能夠訪問json.RawMessage.MarshalJSON即使它不是一個指針。

+0

第三呼叫不調用MarshalJSON(),它使用反映猜測的類型和編碼爲最好是可能的。看看json。(* Encode).Encode()函數:http://golang.org/src/encoding/json/stream.go?s=4283:4330#L173 – divan

+0

@divan怎麼沒有在第二個例子中發生? –

回答

3

當調用任何addressable value的方法,Go會自動引用值來調用用指針接收器的方法。另外,如果非指針值位於可尋址結構中,則它也可以是需要指針接收器的方法的引用。

type Bar struct { 
    Foo Foo 
} 

// b is addressable, therefor so is b.Foo 
b := Bar{ 
    Foo: f, 
} 
b.Foo.Call() 

你的最後一個例子使用了外部結構的地址來獲得富域的地址,並調用MarshalJSON

+0

在第二個示例中,正在堆棧中創建結構體文字,然後將其複製到「Encode」堆棧幀中。爲什麼它不被認爲是「可尋址的」?堆棧中的值是可尋址的。 –

+0

@iliacholy:它是否在堆棧中與規範的尋址能力無關,但在第二個示例中,struct literal的_copy_被分配在堆棧的'interface {}'參數中。接口中的值不可尋址。 – JimB