Go语言中JSON动态字段与结构体匹配的实现咨询
问题解答
你的通配符方案不可行
Go标准库的encoding/json完全不支持json:"*"这种通配符式的标签写法,这么写的话,反序列化程序根本识别不了Data下的动态键,最终Stock字段会是空的,数据根本解析不进来。
最简洁的解决方案:用Map替代固定字段
既然data下面的所有子项结构完全一样,直接把Data定义成map[string]Stock就搞定了,完全不需要用反射,简单又高效。
第一步:修正并定义统一的结构体
// 统一的股票结构体,注意id是字符串类型(原JSON里是"stock1"这种字符串) type Stock struct { ID string `json:"id"` Quote struct { Usd struct { Price float64 `json:"price"` } `json:"USD"` } `json:"quote"` } // 顶层结构体,Data是map类型 type Quotes struct { Data map[string]Stock `json:"data"` }
提醒:你之前把
ID定义成int是错的,原JSON里的id是字符串,这么写会导致反序列化失败,必须改成string。
第二步:正常反序列化并使用数据
var quotes Quotes if err := json.Unmarshal(respBody, "es); err != nil { fmt.Println(err) os.Exit(1) } // 遍历所有股票数据 for stockKey, stockInfo := range quotes.Data { fmt.Printf("股票键:%s,ID:%s,价格:%.2f\n", stockKey, stockInfo.ID, stockInfo.Quote.Usd.Price) }
关于反射的补充(不推荐,仅作了解)
如果非要折腾反射(完全没必要,map方案足够好用),思路是先把JSON反序列化为通用的map[string]interface{},再遍历每个子项,把每个子项单独反序列化为Stock结构体:
// 先反序列化为通用map var rawMap map[string]interface{} if err := json.Unmarshal(respBody, &rawMap); err != nil { fmt.Println(err) os.Exit(1) } // 取出data部分 dataSection, ok := rawMap["data"].(map[string]interface{}) if !ok { fmt.Println("data格式不符合预期") os.Exit(1) } // 遍历解析每个股票 stockMap := make(map[string]Stock) for key, item := range dataSection { // 把interface{}转回JSON字节,再反序列化为Stock itemBytes, err := json.Marshal(item) if err != nil { fmt.Printf("解析键%s失败:%v\n", key, err) continue } var stock Stock if err := json.Unmarshal(itemBytes, &stock); err != nil { fmt.Printf("解析键%s失败:%v\n", key, err) continue } stockMap[key] = stock } // 使用解析后的股票数据 for key, stock := range stockMap { fmt.Printf("股票键:%s,ID:%s,价格:%.2f\n", key, stock.ID, stock.Quote.Usd.Price) }
这种写法比map繁琐,性能也差,除非有特殊需求,否则完全没必要用。
内容的提问来源于stack exchange,提问作者Ramin
相关产品推荐
相关产品推荐

