2017-06-06 58 views
1

在這裏的多晶型JSON解組是一個例子(也參見https://play.golang.org/p/or7z4Xc8tN):嵌入式結構

package main 

import (
    "encoding/json" 
    "fmt" 
) 

type A struct { 
    X string 
    Y int 
} 

type B struct { 
    A 
    Y string 
} 

func main() { 
    data := []byte(`{"X": "me", "Y": "hi"}`) 
    b := &B{} 
    json.Unmarshal(data, b) 
    fmt.Println(b) 
    fmt.Println(b.A) 

    b = &B{} 
    data = []byte(`{"X": "me", "Y": 123}`) 
    json.Unmarshal(data, b) 
    fmt.Println(b) 
    fmt.Println(b.A) 
} 

,其輸出:

&{{me 0} hi} 
{me 0} 
&{{me 0} } 
{me 0} 

有一種方法,以多態解組的字段,Y的任一個int或一個字符串?甚至自B.Y被定義以來,甚至可以解組爲A.Y.

我知道有些人可能會建議用類似於json.Unmarshall(data, &b.A)的方式解組,但我不知道我是否可以將它應用到我當前的設計中。

+0

也許幫助https://stackoverflow.com/questions/32428797/unmarshal-to-a-interface-type –

回答

1

Go的唯一多態是接口。嵌入不提供多態性。

如果您試圖解組JSON,而您不能假定其中某個字段的類型是什麼類型,則可以使用類型爲interface{}的字段以及類型斷言fmt.Sprint或反射。你應該使用哪一個取決於具體的用例 - 一旦你有了價值,你將如何處理它?在某些情況下,您必須注意是否是intstring,這將決定您如何處理價值。

0

正如Adrian所指出的,Go不支持通過結構嵌入進行多態。 interface{}是保存任何類型的golang變量的唯一方法。但是,您可以實現自定義Unmarshaler以將JSON流解碼爲使用json.Numberinterface{}的結構。以下是使用json.Number的實施。對於更通用的interface{}版本,您可以按照Adrian的建議實施它。

func (b *B) UnmarshalJSON(js []byte) error { 
    //First: decode stream to anonymous struct 
    v := struct { 
     X string 
     Y json.Number 
    }{} 

    err := json.Unmarshal(js, &v) 
    if err != nil { 
     return err 
    } 

    //Depends on the v.Y value, choose the holder variable 
    //If it's convertible to number, assign to A.Y 
    //otherwise, assign it to b.Y 
    b.X = v.X 
    if fv, err := v.Y.Float64(); err == nil { 
     b.A.Y = int(fv) 
    } else { 
     b.Y = v.Y.String() 
    } 

    return nil 
} 

工作示例可在The Go Playground中找到。