将json.RawMessage解组为反射切片。

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

Unmarshal json.RawMessage to a reflected slice

问题

在最后一部分,你遇到了一个异常的原因是你试图将json.RawMessage字段解析为一个reflect.Value类型的Go值,但是json.Unmarshal函数无法直接将数组解析为reflect.Value类型。

为了解决这个问题,你可以使用json.Unmarshal函数将json.RawMessage解析为一个临时的切片,然后使用反射将切片的元素逐个添加到reflect.Value类型的切片中。下面是修改后的代码:

  1. // ...
  2. // 创建一个临时的切片用于解析json.RawMessage
  3. var tempSlice []json.RawMessage
  4. err = json.Unmarshal(command.Items, &tempSlice)
  5. if err != nil {
  6. log.Fatalln("error:", err)
  7. }
  8. // 使用反射将切片的元素逐个添加到reflect.Value类型的切片中
  9. for _, item := range tempSlice {
  10. newItem := reflect.New(itemtyp).Interface()
  11. err = json.Unmarshal(item, newItem)
  12. if err != nil {
  13. log.Fatalln("error:", err)
  14. }
  15. rv = reflect.Append(rv, reflect.ValueOf(newItem).Elem())
  16. }
  17. // ...

这样修改后,你就可以成功解析json.RawMessage字段并将其转换为reflect.Value类型的切片了。

英文:

In the following sample, i am trying to Unmarshal a json.RawMessage into a slice using reflection to figure out the type of the items in the json.RawMessage, the json.RawMessage always represents an array of a specific type, the name of the type is included in the json and a pointer to it is retrieved from a map[string]interface{}

  1. type command struct {
  2. Action *string
  3. Type *string
  4. Items json.RawMessage //because i need to figure out the Type field value first, its always an array of a single type
  5. }
  6. //a sample model
  7. type Chicken struct {
  8. Id *int
  9. Name *string
  10. EggColor *string
  11. }
  12. //this map contains a pointer to each needed struct using reflection i can get the type and make a SliceOf it
  13. var ModelRegistery map[string]interface {}
  14. func main(){
  15. //register the Chicken type to retrieve a pointer to it using a string key
  16. var chickenPtr *Chicken
  17. ModelRegistery = make(map[string]interface {})
  18. ModelRegistery["Chicken"] = chickenPtr
  19. //some json for testing
  20. cJson := []byte(`{"Action":"BURN",
  21. "Type":"Chicken",
  22. "Items":[{"Id":1,"Name":"B","EggColor":"D"},
  23. {"Id":2,"Name":"M","EggColor":"C"}]}`)
  24. var command command
  25. err := json.Unmarshal(cJson,&command)
  26. if err != nil {
  27. log.Fatalln("error:", err)
  28. }
  29. //get the type from the model registry and reflect it
  30. itemtyp := reflect.TypeOf(ModelRegistery[(*command.Type)]).Elem()
  31. //create a slice of the type
  32. itemslice := reflect.SliceOf(itemtyp)
  33. rv := reflect.MakeSlice(itemslice, 0, 2)
  34. //now when trying to unmarshal the json.RawMessage field i get an exception
  35. err = json.Unmarshal(command.Items,&rv)
  36. if err != nil {
  37. log.Fatalln("error:", err) //error: json: cannot unmarshal array into Go value of type reflect.Value
  38. }
  39. }

the question is, what am i doing wrong in the last part? why do i get the exception?

  1. json: cannot unmarshal array into Go value of type reflect.Value

here is a goplay
http://play.golang.org/p/63dxgnPFz_

答案1

得分: 3

你需要将interface{}传递给unmarshal函数,而不是reflect.Value。

更改以下部分似乎可以解决问题:

  1. itemslice := reflect.SliceOf(itemtyp)
  2. rv := reflect.New(itemslice)
  3. //现在尝试对json.RawMessage字段进行解组时会出现异常
  4. err = json.Unmarshal(command.Items, rv.Interface())
英文:

You need to pass interface{} to the unmarhsal function, not a reflect.Value.

Changing the following seems to work:

  1. itemslice := reflect.SliceOf(itemtyp)
  2. rv := reflect.New(itemslice)
  3. //now when trying to unmarshal the json.RawMessage field i get an exception
  4. err = json.Unmarshal(command.Items, rv.Interface())

huangapple
  • 本文由 发表于 2014年7月30日 17:46:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/25033662.html
匿名

发表评论

匿名网友

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

确定