将JSON解组为反射结构体。

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

Unmarshal json to reflected struct

问题

可以使用反射将JSON解组成一个由反射创建的结构体,而无需硬编码原始类型。在这个例子中,你可以使用以下代码:

  1. package main
  2. import (
  3. "fmt"
  4. "encoding/json"
  5. "reflect"
  6. )
  7. type Employee struct {
  8. Firstname string `json:"firstname"`
  9. }
  10. func main() {
  11. // 原始结构体
  12. orig := new(Employee)
  13. t := reflect.TypeOf(orig)
  14. v := reflect.New(t.Elem())
  15. // 反射结构体
  16. new := v.Elem().Interface()
  17. // 解组到反射结构体
  18. json.Unmarshal([]byte(`{"firstname": "bender"}`), &new)
  19. fmt.Printf("%+v\n", new)
  20. }

在这个例子中,我们使用了类型断言将new转换为Employee类型。但是,如果你不知道类型,可以直接使用v进行解组,但是结构体将会被置零:

  1. json.Unmarshal([]byte(`{"firstname": "bender"}`), v)

如果省略类型断言,你将得到一个映射(map),这是可以理解的:

  1. json.Unmarshal([]byte(`{"firstname": "bender"}`), v.Elem().Interface())

希望这可以帮助到你!

英文:

Is it possible to unmarshal JSON into a struct made from reflection without hardcoding the original type?

<!-- language: golang -->

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;encoding/json&quot;
  5. &quot;reflect&quot;
  6. )
  7. type Employee struct {
  8. Firstname string `json:&quot;firstname&quot;`
  9. }
  10. func main() {
  11. //Original struct
  12. orig := new(Employee)
  13. t := reflect.TypeOf(orig)
  14. v := reflect.New(t.Elem())
  15. //Reflected struct
  16. new := v.Elem().Interface().(Employee)
  17. // Unmarshal to reflected struct
  18. json.Unmarshal([]byte(&quot;{\&quot;firstname\&quot;: \&quot;bender\&quot;}&quot;), &amp;new)
  19. fmt.Printf(&quot;%+v\n&quot;, new)
  20. }

I used a cast to Employee in this example. But what if i don't know the type?

When i just use v for the unmarhaling the struct will be zeroed.

  1. json.Unmarshal([]byte(&quot;{\&quot;firstname\&quot;: \&quot;bender\&quot;}&quot;), v)

When I omit the cast I get a map. which is understandable

  1. json.Unmarshal([]byte(&quot;{\&quot;firstname\&quot;: \&quot;bender\&quot;}&quot;), v.Elem().Interface())

答案1

得分: 17

问题在于,如果你在这里省略类型断言:

  1. new := v.Elem().Interface()

new 的类型会被推断为 interface{}

然后,当你取地址进行解组时,&new 的类型是 *interface{}(指向接口的指针),而解组的结果并不符合你的期望。

如果你直接使用指针引用,可以避免类型断言。

  1. func main() {
  2. // 原始结构体
  3. orig := new(Employee)
  4. t := reflect.TypeOf(orig)
  5. v := reflect.New(t.Elem())
  6. // 反射指针
  7. newP := v.Interface()
  8. // 解组到反射的结构体指针
  9. json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), newP)
  10. fmt.Printf("%+v\n", newP)
  11. }

Playground: https://play.golang.org/p/lTBU-1PqM4

英文:

The problem here is that if you omit the type assertion here:

  1. new := v.Elem().Interface()

The new is inferred to have a interface{} type.

Then when you take the address to unmarshal, the type of &amp;new is *interface{} (pointer to interface{}) and unmarshal does not work as you expect.

You can avoid the type assertion if instead of getting the Elem() you work directly with the pointer reference.

  1. func main() {
  2. //Original struct
  3. orig := new(Employee)
  4. t := reflect.TypeOf(orig)
  5. v := reflect.New(t.Elem())
  6. // reflected pointer
  7. newP := v.Interface()
  8. // Unmarshal to reflected struct pointer
  9. json.Unmarshal([]byte(&quot;{\&quot;firstname\&quot;: \&quot;bender\&quot;}&quot;), newP)
  10. fmt.Printf(&quot;%+v\n&quot;, newP)
  11. }

Playground: https://play.golang.org/p/lTBU-1PqM4

答案2

得分: 3

  1. // https://github.com/xiaojun207/go-base-utils/blob/master/utils/Clone.go
  2. func NewInterface(typ reflect.Type, data []byte) interface{} {
  3. if typ.Kind() == reflect.Ptr {
  4. typ = typ.Elem()
  5. dst := reflect.New(typ).Elem()
  6. json.Unmarshal(data, dst.Addr().Interface())
  7. return dst.Addr().Interface()
  8. }else {
  9. dst := reflect.New(typ).Elem()
  10. json.Unmarshal(data, dst.Addr().Interface())
  11. return dst.Interface()
  12. }
  13. }
  14. type Employee struct {
  15. Firstname string `json:"firstname"`
  16. }
  17. func main() {
  18. data := "{\"firstName\": \"John\"}"
  19. obj := NewInterface(reflect.TypeOf(Employee{}), []byte(data))
  20. fmt.Println("Employee:", obj)
  21. }

这是一段Go语言代码,它定义了一个名为NewInterface的函数和一个名为Employee的结构体。NewInterface函数根据给定的类型和数据创建一个新的接口对象。如果类型是指针类型,它会创建一个指向该类型的指针,并将数据解析为该类型的对象。如果类型不是指针类型,它会创建一个该类型的对象,并将数据解析为该对象。Employee结构体定义了一个名为Firstname的字符串字段。

main函数中,它使用NewInterface函数创建了一个Employee对象,并将数据{"firstName": "John"}解析为该对象。然后,它打印输出了该对象。

请注意,代码中的json:"firstname"是用于指定结构体字段在JSON序列化和反序列化时的名称的标签。

英文:
  1. // https://github.com/xiaojun207/go-base-utils/blob/master/utils/Clone.go
  2. func NewInterface(typ reflect.Type, data []byte) interface{} {
  3. if typ.Kind() == reflect.Ptr {
  4. typ = typ.Elem()
  5. dst := reflect.New(typ).Elem()
  6. json.Unmarshal(data, dst.Addr().Interface())
  7. return dst.Addr().Interface()
  8. }else {
  9. dst := reflect.New(typ).Elem()
  10. json.Unmarshal(data, dst.Addr().Interface())
  11. return dst.Interface()
  12. }
  13. }
  14. type Employee struct {
  15. Firstname string `json:&quot;firstname&quot;`
  16. }
  17. func main() {
  18. data := &quot;{\&quot;firstName\&quot;: \&quot;John\&quot;}&quot;
  19. obj := NewInterface(reflect.TypeOf(Employee{}), []byte(data))
  20. fmt.Println(&quot;Employee:&quot;, obj)
  21. }

答案3

得分: 0

如果您完全不知道类型,可以将JSON字符串解组为interface{}。如果您需要处理解组后的数据,可以将其转换为所需的类型。

这里有一个示例:

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "reflect"
  6. "unsafe"
  7. )
  8. type Employee struct {
  9. Firstname string `json:"firstName"`
  10. }
  11. func deserialize(jsonData string) interface{} {
  12. var obj interface{}
  13. if err := json.Unmarshal([]byte(jsonData), &obj); err != nil {
  14. panic(err)
  15. }
  16. return obj
  17. }
  18. func NewEmployee(objData map[string]interface{}) *Employee {
  19. s := (*Employee)(nil)
  20. t := reflect.TypeOf(s).Elem()
  21. employeePtr := reflect.New(t)
  22. employee := (*Employee)(unsafe.Pointer(employeePtr.Pointer()))
  23. employee.Firstname = objData["firstName"].(string)
  24. return employee
  25. }
  26. func main() {
  27. jsonData := `{"firstName": "John"}`
  28. obj := deserialize(jsonData)
  29. objData := obj.(map[string]interface{})
  30. employee := NewEmployee(objData)
  31. fmt.Printf("%s\n", employee.Firstname)
  32. }

您可以在Go Playground上进行测试。

英文:

If you don't know the type at all, you can Unmarshal the JSON string into an interface{}. If you then need to work with the Unmarshaled data, you can convert it to the desired type.

Here's an example:

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;fmt&quot;
  5. &quot;reflect&quot;
  6. &quot;unsafe&quot;
  7. )
  8. type Employee struct {
  9. Firstname string `json:&quot;firstName&quot;`
  10. }
  11. func deserialize(jsonData string) interface{} {
  12. var obj interface{}
  13. if err := json.Unmarshal([]byte(jsonData), &amp;obj); err != nil {
  14. panic(err)
  15. }
  16. return obj
  17. }
  18. func NewEmployee(objData map[string]interface{}) *Employee {
  19. s := (*Employee)(nil)
  20. t := reflect.TypeOf(s).Elem()
  21. employeePtr := reflect.New(t)
  22. employee := (*Employee)(unsafe.Pointer(employeePtr.Pointer()))
  23. employee.Firstname = objData[&quot;firstName&quot;].(string)
  24. return employee
  25. }
  26. func main() {
  27. jsonData := &quot;{\&quot;firstName\&quot;: \&quot;John\&quot;}&quot;
  28. obj := deserialize(jsonData)
  29. objData := obj.(map[string]interface{})
  30. employee := NewEmployee(objData)
  31. fmt.Printf(&quot;%s\n&quot;, employee.Firstname)
  32. }

You can check it on the Go Playground.

huangapple
  • 本文由 发表于 2017年8月15日 00:57:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/45679408.html
匿名

发表评论

匿名网友

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

确定