英文:
In Go Language, how do I unmarshal json to array of object?
问题
type Monster struct {
MonsterId  int32
Level      int32
SkillLevel int32
AimerId    int32
}
type MonsterCollection struct {
Pool map[string]Monster
}
func (mc *MonsterCollection) FromJson(jsonStr string) {
var data interface{}
b := []byte(jsonStr)
err := json.Unmarshal(b, &data)
if err != nil {
return
}
m := data.(map[string]interface{})
i := 0
for k, v := range m {
    monster := new(Monster)
    monster.Level = v["level"].(int32)
    monster.MonsterId = v["monster-id"].(int32)
    monster.SkillLevel = v["skill-level"].(int32)
    monster.AimerId = v["aimer-id"].(int32)
    mc.Pool[i] = *monster
    i++
}
}
英文:
I have the following JSON, and I want to parse it into array of class:
{
	"1001": {"level":10, "monster-id": 1001, "skill-level": 1, "aimer-id": 301}
	"1002": {"level":12, "monster-id": 1002, "skill-level": 1, "aimer-id": 302}
	"1003": {"level":16, "monster-id": 1003, "skill-level": 2, "aimer-id": 303}
}
Here is what i am trying to do but failed:
type Monster struct {
	MonsterId  int32
	Level      int32
	SkillLevel int32
	AimerId    int32
}
type MonsterCollection struct {
	Pool map[string]Monster
}
func (mc *MonsterCollection) FromJson(jsonStr string) {
	var data interface{}
	b := []byte(jsonStr)
	err := json.Unmarshal(b, &data)
	if err != nil {
		return
	}
	m := data.(map[string]interface{})
	i := 0
	for k, v := range m {
		monster := new(Monster)
		monster.Level = v["level"]
		monster.MonsterId = v["monster-id"]
		monster.SkillLevel = v["skill-level"]
		monster.AimerId = v["aimer-id"]
		mc.Pool[i] = monster
		i++
	}
}
The compiler complain about the  v["level"]
<< invalid operation. index of type interface().
答案1
得分: 19
这段代码有很多错误。首先,json不是有效的json。你在顶层对象的键值对之间缺少了逗号。我为你添加了逗号并进行了漂亮的打印:
{
   "1001":{
      "level":10,
      "monster-id":1001,
      "skill-level":1,
      "aimer-id":301
   },
   "1002":{
      "level":12,
      "monster-id":1002,
      "skill-level":1,
      "aimer-id":302
   },
   "1003":{
      "level":16,
      "monster-id":1003,
      "skill-level":2,
      "aimer-id":303
   }
}
你下一个问题(你提到的问题)是m := data.(map[string]interface{})使m成为了map[string]interface{}。这意味着当你在range循环中索引它时,类型是interface{}。你需要再次使用类型断言v.(map[string]interface{}),然后每次从map中读取时都进行类型断言。
我还注意到你下一个尝试mc.Pool[i] = monster,当i是int类型而mc.Pool是map[string]Monster类型时。int不是该map的有效键。
你的数据看起来非常固定,所以我建议让unmarshal为你完成大部分工作。你可以提供一个map[string]Monster给它,而不是map[string]interface{}。
这是一个快速的示例。除了改变unmarshalling的工作方式之外,我还添加了一个错误返回。错误返回对于查找错误很有用。这个错误返回告诉我你的json是无效的。
type Monster struct {
	MonsterId  int32 `json:"monster-id"`
	Level      int32 `json:"level"`
	SkillLevel int32 `json:"skill-level"`
	AimerId    int32 `json:"aimer-id"`
}
type MonsterCollection struct {
	Pool map[string]Monster
}
func (mc *MonsterCollection) FromJson(jsonStr string) error {
	var data = &mc.Pool
	b := []byte(jsonStr)
	return json.Unmarshal(b, data)
}
我在goplay上发布了一个可工作的示例:http://play.golang.org/p/4EaasS2VLL
英文:
This code has many errors in it. To start with, the json isn't valid json. You are missing the commas in between key pairs in your top level object. I added the commas and pretty printed it for you:
{
   "1001":{
      "level":10,
      "monster-id":1001,
      "skill-level":1,
      "aimer-id":301
   },
   "1002":{
      "level":12,
      "monster-id":1002,
      "skill-level":1,
      "aimer-id":302
   },
   "1003":{
      "level":16,
      "monster-id":1003,
      "skill-level":2,
      "aimer-id":303
   }
}
Your next problem (the one you asked about) is that m := data.(map[string]interface{}) makes m a map[string]interface{}. That means when you index it such as the v in your range loop, the type is interface{}. You need to type assert it again with v.(map[string]interface{}) and then type assert each time you read from the map.
I also notice that you next attempt mc.Pool[i] = monster when i is an int and mc.Pool is a map[string]Monster. An int is not a valid key for that map.
Your data looks very rigid so I would make unmarshall do most of the work for you. Instead of providing it a map[string]interface{}, you can provide it a map[string]Monster.
Here is a quick example. As well as changing how the unmarshalling works, I also added an error return. The error return is useful for finding bugs. That error return is what told me you had invalid json.
type Monster struct {
	MonsterId  int32 `json:"monster-id"`
	Level      int32 `json:"level"`
	SkillLevel int32 `json:"skill-level"`
	AimerId    int32 `json:"aimer-id"`
}
type MonsterCollection struct {
	Pool map[string]Monster
}
func (mc *MonsterCollection) FromJson(jsonStr string) error {
	var data = &mc.Pool
	b := []byte(jsonStr)
	return json.Unmarshal(b, data)
}
I posted a working example to goplay: http://play.golang.org/p/4EaasS2VLL
答案2
得分: 0
稍微偏离一边 - 当你需要一个映射时,你要求一个对象数组
如果你需要一个数组(实际上是一个切片)
http://ioblocks.blogspot.com/2014/09/loading-arrayslice-of-objects-from-json.html
英文:
Slightly off to one side - you asked for an array of objects when you needed a map
If you need an array (actually a slice)
http://ioblocks.blogspot.com/2014/09/loading-arrayslice-of-objects-from-json.html
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论