在Go语言中,我如何将JSON解组为对象数组?

huangapple go评论82阅读模式
英文:

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:

{
   &quot;1001&quot;:{
      &quot;level&quot;:10,
      &quot;monster-id&quot;:1001,
      &quot;skill-level&quot;:1,
      &quot;aimer-id&quot;:301
   },
   &quot;1002&quot;:{
      &quot;level&quot;:12,
      &quot;monster-id&quot;:1002,
      &quot;skill-level&quot;:1,
      &quot;aimer-id&quot;:302
   },
   &quot;1003&quot;:{
      &quot;level&quot;:16,
      &quot;monster-id&quot;:1003,
      &quot;skill-level&quot;:2,
      &quot;aimer-id&quot;: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:&quot;monster-id&quot;`
	Level      int32 `json:&quot;level&quot;`
	SkillLevel int32 `json:&quot;skill-level&quot;`
	AimerId    int32 `json:&quot;aimer-id&quot;`
}

type MonsterCollection struct {
	Pool map[string]Monster
}

func (mc *MonsterCollection) FromJson(jsonStr string) error {
	var data = &amp;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

huangapple
  • 本文由 发表于 2013年6月5日 12:20:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/16931499.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定