2017-08-14 112 views
2

是否有可能解开JSON到反射而不是硬编码原始类型的结构?Unmarshal json反射结构

package main 

import (
    "fmt" 
    "encoding/json" 
    "reflect" 
) 

type Employee struct { 
    Firstname string  `json:"firstname"` 
} 

func main() { 
    //Original struct 
    orig := new(Employee) 

    t := reflect.TypeOf(orig) 
    v := reflect.New(t.Elem()) 

    //Reflected struct 
    new := v.Elem().Interface().(Employee) 

    // Unmarshal to reflected struct 
    json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), &new) 

    fmt.Printf("%+v\n", new) 
} 

在这个例子中,我使用了cast到Employee。但是如果我不知道这种类型呢?

当我只使用v进行非标注时,结构将被清零。

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

当我省略演员时,我得到一张地图。这是可以理解

json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), v.Elem().Interface()) 
+0

只因为它是真的伤害了我的眼睛:为什么你有一个叫'新'的变种?在更灵活的&Employee {}'上使用'new(Employee)'有什么意义? –

回答

2

这里的问题是,如果你忽略了类型断言这里:

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

new推断有interface{}类型。

然后,当您取消编组地址时,&new的类型为*interface{}(指向接口{}的指针),解组无法按预期工作。

如果不是直接使用指针引用获得Elem(),则可以避免类型断言。

func main() { 
    //Original struct 
    orig := new(Employee) 

    t := reflect.TypeOf(orig) 
    v := reflect.New(t.Elem()) 

    // reflected pointer 
    newP := v.Interface() 

    // Unmarshal to reflected struct pointer 
    json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), newP) 

    fmt.Printf("%+v\n", newP) 
} 

游乐场:https://play.golang.org/p/lTBU-1PqM4

+0

谢谢。这非常合理 – Slemgrim

0

如果你不知道类型的一切,你可以解编JSON字符串的接口{}。如果您需要使用解组数据,则可以将其转换为所需的类型。

下面是一个例子:

package main 

import (
    "encoding/json" 
    "fmt" 
    "reflect" 
    "unsafe" 
) 

type Employee struct { 
    Firstname string `json:"firstName"` 
} 

func deserialize(jsonData string) interface{} { 
    var obj interface{} 

    if err := json.Unmarshal([]byte(jsonData), &obj); err != nil { 
     panic(err) 
    } 

    return obj 
} 

func NewEmployee(objData map[string]interface{}) *Employee { 
    s := (*Employee)(nil) 
    t := reflect.TypeOf(s).Elem() 
    employeePtr := reflect.New(t) 
    employee := (*Employee)(unsafe.Pointer(employeePtr.Pointer())) 
    employee.Firstname = objData["firstName"].(string) 

    return employee 
} 

func main() { 
    jsonData := "{\"firstName\": \"John\"}" 

    obj := deserialize(jsonData) 

    objData := obj.(map[string]interface{}) 
    employee := NewEmployee(objData) 

    fmt.Printf("%s\n", employee.Firstname) 
} 

您可以检查它的Go Playground