如何解码为嵌入式结构?
How can I decode to an embedded struct?
我希望能够在响应主体上使用 .Decode()
来填充结构,而不必首先尝试找出我应该解码为哪种类型的结构。
我有一个通用结构 Match
来保存有关已玩游戏的信息,例如Fortnite 中的一场比赛。在这个结构中,我使用 MatchData
来保存整个游戏的比赛数据。
当解码到 MatchData
结构时,我发现底层嵌入类型已初始化,但所有默认值均已初始化,而不是响应中的值。
type Match struct {
MatchID int `json:"match_id"`
GameType int `json:"game_type"`
MatchData *MatchData `json:"match_data"`
}
type MatchData struct {
MatchGame1
MatchGame2
}
type MatchGame1 struct {
X int `json:"x"`
Y int `json:"y"`
}
type MatchGame2 struct {
X int `json:"x"`
Y int `json:"y"`
}
func populateData(m *Match) (Match, error) {
response, err := http.Get("game1.com/path")
if err != nil {
return nil, err
}
// Here, m.MatchData is set with X and Y equal to 0
// when response contains values > 0
err = json.NewDecoder(response.Body).Decode(&m.MatchData)
if err != nil {
return nil, err
}
return m, nil
}
编辑
示例预期 JSON 有效负载。
{
"x": 10,
"y": 20
}
我可以通过检查 m.GameType
,创建一个对应的结构然后将其分配给 m.MatchData
来解决问题,但是如果我想添加另外 100 个游戏 API,我更愿意该功能可能与它无关。
我不确定这是否可行,但在此先感谢。
问题中的方法将不起作用,因为嵌入式结构共享字段名称。试试这个方法。
声明一个映射,将游戏类型标识符与关联的围棋类型相关联。这只是与解码有关的代码,了解数百种游戏类型。
var gameTypes = map[int]reflect.Type{
1: reflect.TypeOf(&MatchGame1{}),
2: reflect.TypeOf(&MatchGame2{}),
}
将匹配数据解码为raw message。使用游戏类型创建匹配数据值并解码为该值。
func decodeMatch(r io.Reader) (*Match, error) {
// Start with match data set to a raw messae.
var raw json.RawMessage
m := &Match{MatchData: &raw}
err := json.NewDecoder(r).Decode(m)
if err != nil {
return nil, err
}
m.MatchData = nil
// We are done if there's no raw message.
if len(raw) == 0 {
return m, nil
}
// Create the required match data value.
t := gameTypes[m.GameType]
if t == nil {
return nil, errors.New("unknown game type")
}
m.MatchData = reflect.New(t.Elem()).Interface()
// Decode the raw message to the match data.
return m, json.Unmarshal(raw, m.MatchData)
}
我希望能够在响应主体上使用 .Decode()
来填充结构,而不必首先尝试找出我应该解码为哪种类型的结构。
我有一个通用结构 Match
来保存有关已玩游戏的信息,例如Fortnite 中的一场比赛。在这个结构中,我使用 MatchData
来保存整个游戏的比赛数据。
当解码到 MatchData
结构时,我发现底层嵌入类型已初始化,但所有默认值均已初始化,而不是响应中的值。
type Match struct {
MatchID int `json:"match_id"`
GameType int `json:"game_type"`
MatchData *MatchData `json:"match_data"`
}
type MatchData struct {
MatchGame1
MatchGame2
}
type MatchGame1 struct {
X int `json:"x"`
Y int `json:"y"`
}
type MatchGame2 struct {
X int `json:"x"`
Y int `json:"y"`
}
func populateData(m *Match) (Match, error) {
response, err := http.Get("game1.com/path")
if err != nil {
return nil, err
}
// Here, m.MatchData is set with X and Y equal to 0
// when response contains values > 0
err = json.NewDecoder(response.Body).Decode(&m.MatchData)
if err != nil {
return nil, err
}
return m, nil
}
编辑 示例预期 JSON 有效负载。
{
"x": 10,
"y": 20
}
我可以通过检查 m.GameType
,创建一个对应的结构然后将其分配给 m.MatchData
来解决问题,但是如果我想添加另外 100 个游戏 API,我更愿意该功能可能与它无关。
我不确定这是否可行,但在此先感谢。
问题中的方法将不起作用,因为嵌入式结构共享字段名称。试试这个方法。
声明一个映射,将游戏类型标识符与关联的围棋类型相关联。这只是与解码有关的代码,了解数百种游戏类型。
var gameTypes = map[int]reflect.Type{
1: reflect.TypeOf(&MatchGame1{}),
2: reflect.TypeOf(&MatchGame2{}),
}
将匹配数据解码为raw message。使用游戏类型创建匹配数据值并解码为该值。
func decodeMatch(r io.Reader) (*Match, error) {
// Start with match data set to a raw messae.
var raw json.RawMessage
m := &Match{MatchData: &raw}
err := json.NewDecoder(r).Decode(m)
if err != nil {
return nil, err
}
m.MatchData = nil
// We are done if there's no raw message.
if len(raw) == 0 {
return m, nil
}
// Create the required match data value.
t := gameTypes[m.GameType]
if t == nil {
return nil, errors.New("unknown game type")
}
m.MatchData = reflect.New(t.Elem()).Interface()
// Decode the raw message to the match data.
return m, json.Unmarshal(raw, m.MatchData)
}