2017-08-14 71 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