如何正确地反序列化不同类型的数组?

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

How to unmarshall an array of different types correctly?

问题

只要我有键值对,解组就很简单,但是如何解组一个不同类型的数组并且顺序不同呢?单个元素是明确定义和已知的,但是顺序不确定。

我想不出一个优雅的解决方案。

我应该尝试所有元素吗?
是否有一种可以为我做到这一点的联合类型?

playground版本

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. var my_json string = `{
  7. "an_array":[
  8. "with_a string",
  9. {
  10. "and":"some_more",
  11. "different":["nested", "types"]
  12. }
  13. ]
  14. }`
  15. type MyInner struct {
  16. And string
  17. Different []string
  18. }
  19. type MyJSON struct {
  20. An_array []json.RawMessage
  21. }
  22. func main() {
  23. var my_json_test MyJSON
  24. e := json.Unmarshal([]byte(my_json), &my_json_test)
  25. if e != nil {
  26. fmt.Println(e)
  27. } else {
  28. for index, value := range my_json_test.An_array {
  29. fmt.Println("index: ", index)
  30. fmt.Println("value: ", string(value))
  31. }
  32. var my_inner MyInner
  33. err := json.Unmarshal(my_json_test.An_array[1], &my_inner)
  34. if err != nil {
  35. fmt.Println(err)
  36. } else {
  37. fmt.Println("inner structure: ", my_inner)
  38. }
  39. }
  40. }
英文:

As long as I have key-value pairs unmarshalling is pretty straight forward but how would I unmarshall an array of different types in different order? The single elements are well defined and known but the order is not.

I can not come up with a beautiful solution.

Would I try and error over all elements?
Is there some kind of union type that could do that for me?

playground version

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. var my_json string = `{
  7. "an_array":[
  8. "with_a string",
  9. {
  10. "and":"some_more",
  11. "different":["nested", "types"]
  12. }
  13. ]
  14. }`
  15. type MyInner struct {
  16. And string
  17. Different []string
  18. }
  19. type MyJSON struct {
  20. An_array []json.RawMessage
  21. }
  22. func main() {
  23. var my_json_test MyJSON
  24. e := json.Unmarshal([]byte(my_json), &my_json_test)
  25. if e != nil {
  26. fmt.Println(e)
  27. } else {
  28. for index, value := range my_json_test.An_array {
  29. fmt.Println("index: ", index)
  30. fmt.Println("value: ", string(value))
  31. }
  32. var my_inner MyInner
  33. err := json.Unmarshal(my_json_test.An_array[1], &my_inner)
  34. if err != nil {
  35. fmt.Println(err)
  36. } else {
  37. fmt.Println("inner structure: ", my_inner)
  38. }
  39. }
  40. }

答案1

得分: 22

Go官方博客有一篇关于encoding/json的好文章:JSON和GO。可以将任意数据解码为interface{},并使用类型断言来动态确定类型。

你的代码可以修改为以下形式:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. var my_json string = `{
  7. "an_array":[
  8. "with_a string",
  9. {
  10. "and":"some_more",
  11. "different":["nested", "types"]
  12. }
  13. ]
  14. }`
  15. func WTHisThisJSON(f interface{}) {
  16. switch vf := f.(type) {
  17. case map[string]interface{}:
  18. fmt.Println("是一个map:")
  19. for k, v := range vf {
  20. switch vv := v.(type) {
  21. case string:
  22. fmt.Printf("%v: 是字符串 - %q\n", k, vv)
  23. case int:
  24. fmt.Printf("%v: 是整数 - %q\n", k, vv)
  25. default:
  26. fmt.Printf("%v: ", k)
  27. WTHisThisJSON(v)
  28. }
  29. }
  30. case []interface{}:
  31. fmt.Println("是一个数组:")
  32. for k, v := range vf {
  33. switch vv := v.(type) {
  34. case string:
  35. fmt.Printf("%v: 是字符串 - %q\n", k, vv)
  36. case int:
  37. fmt.Printf("%v: 是整数 - %q\n", k, vv)
  38. default:
  39. fmt.Printf("%v: ", k)
  40. WTHisThisJSON(v)
  41. }
  42. }
  43. }
  44. }
  45. func main() {
  46. fmt.Println("JSON:\n", my_json, "\n")
  47. var f interface{}
  48. err := json.Unmarshal([]byte(my_json), &f)
  49. if err != nil {
  50. fmt.Println(err)
  51. } else {
  52. fmt.Printf("JSON: ")
  53. WTHisThisJSON(f)
  54. }
  55. }

它的输出如下:

  1. JSON:
  2. {
  3. "an_array":[
  4. "with_a string",
  5. {
  6. "and":"some_more",
  7. "different":["nested", "types"]
  8. }
  9. ]
  10. }
  11. JSON: 是一个map
  12. an_array: 是一个数组:
  13. 0: 是字符串 - "with_a string"
  14. 1: 是一个map
  15. and: 是字符串 - "some_more"
  16. different: 是一个数组:
  17. 0: 是字符串 - "nested"
  18. 1: 是字符串 - "types"

它还不完整,但展示了它将如何工作。

英文:

Go official blog has a nice article about encoding/json: JSON and GO. It's possible to "Decode arbitrary data" into an interface{} and use type assertion to determine the type dynamically.

Your code can be probably modified to this:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. var my_json string = `{
  7. "an_array":[
  8. "with_a string",
  9. {
  10. "and":"some_more",
  11. "different":["nested", "types"]
  12. }
  13. ]
  14. }`
  15. func WTHisThisJSON(f interface{}) {
  16. switch vf := f.(type) {
  17. case map[string]interface{}:
  18. fmt.Println("is a map:")
  19. for k, v := range vf {
  20. switch vv := v.(type) {
  21. case string:
  22. fmt.Printf("%v: is string - %q\n", k, vv)
  23. case int:
  24. fmt.Printf("%v: is int - %q\n", k, vv)
  25. default:
  26. fmt.Printf("%v: ", k)
  27. WTHisThisJSON(v)
  28. }
  29. }
  30. case []interface{}:
  31. fmt.Println("is an array:")
  32. for k, v := range vf {
  33. switch vv := v.(type) {
  34. case string:
  35. fmt.Printf("%v: is string - %q\n", k, vv)
  36. case int:
  37. fmt.Printf("%v: is int - %q\n", k, vv)
  38. default:
  39. fmt.Printf("%v: ", k)
  40. WTHisThisJSON(v)
  41. }
  42. }
  43. }
  44. }
  45. func main() {
  46. fmt.Println("JSON:\n", my_json, "\n")
  47. var f interface{}
  48. err := json.Unmarshal([]byte(my_json), &f)
  49. if err != nil {
  50. fmt.Println(err)
  51. } else {
  52. fmt.Printf("JSON: ")
  53. WTHisThisJSON(f)
  54. }
  55. }

It gives output as follows:

  1. JSON:
  2. {
  3. "an_array":[
  4. "with_a string",
  5. {
  6. "and":"some_more",
  7. "different":["nested", "types"]
  8. }
  9. ]
  10. }
  11. JSON: is a map:
  12. an_array: is an array:
  13. 0: is string - "with_a string"
  14. 1: is a map:
  15. and: is string - "some_more"
  16. different: is an array:
  17. 0: is string - "nested"
  18. 1: is string - "types"

It's not complete yet, but shows how it's gonna work.

huangapple
  • 本文由 发表于 2012年11月14日 00:02:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/13364181.html
匿名

发表评论

匿名网友

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

确定