英文:
Unmarshal json to reflected struct
问题
可以使用反射将JSON解组成一个由反射创建的结构体,而无需硬编码原始类型。在这个例子中,你可以使用以下代码:
package main
import (
"fmt"
"encoding/json"
"reflect"
)
type Employee struct {
Firstname string `json:"firstname"`
}
func main() {
// 原始结构体
orig := new(Employee)
t := reflect.TypeOf(orig)
v := reflect.New(t.Elem())
// 反射结构体
new := v.Elem().Interface()
// 解组到反射结构体
json.Unmarshal([]byte(`{"firstname": "bender"}`), &new)
fmt.Printf("%+v\n", new)
}
在这个例子中,我们使用了类型断言将new
转换为Employee
类型。但是,如果你不知道类型,可以直接使用v
进行解组,但是结构体将会被置零:
json.Unmarshal([]byte(`{"firstname": "bender"}`), v)
如果省略类型断言,你将得到一个映射(map),这是可以理解的:
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 -->
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)
}
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.
json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), v)
When I omit the cast I get a map. which is understandable
json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), v.Elem().Interface())
答案1
得分: 17
问题在于,如果你在这里省略类型断言:
new := v.Elem().Interface()
new
的类型会被推断为 interface{}
。
然后,当你取地址进行解组时,&new
的类型是 *interface{}
(指向接口的指针),而解组的结果并不符合你的期望。
如果你直接使用指针引用,可以避免类型断言。
func main() {
// 原始结构体
orig := new(Employee)
t := reflect.TypeOf(orig)
v := reflect.New(t.Elem())
// 反射指针
newP := v.Interface()
// 解组到反射的结构体指针
json.Unmarshal([]byte("{\"firstname\": \"bender\"}"), newP)
fmt.Printf("%+v\n", newP)
}
Playground: https://play.golang.org/p/lTBU-1PqM4
英文:
The problem here is that if you omit the type assertion here:
new := v.Elem().Interface()
The new
is inferred to have a interface{}
type.
Then when you take the address to unmarshal, the type of &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.
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)
}
Playground: https://play.golang.org/p/lTBU-1PqM4
答案2
得分: 3
// https://github.com/xiaojun207/go-base-utils/blob/master/utils/Clone.go
func NewInterface(typ reflect.Type, data []byte) interface{} {
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
dst := reflect.New(typ).Elem()
json.Unmarshal(data, dst.Addr().Interface())
return dst.Addr().Interface()
}else {
dst := reflect.New(typ).Elem()
json.Unmarshal(data, dst.Addr().Interface())
return dst.Interface()
}
}
type Employee struct {
Firstname string `json:"firstname"`
}
func main() {
data := "{\"firstName\": \"John\"}"
obj := NewInterface(reflect.TypeOf(Employee{}), []byte(data))
fmt.Println("Employee:", obj)
}
这是一段Go语言代码,它定义了一个名为NewInterface
的函数和一个名为Employee
的结构体。NewInterface
函数根据给定的类型和数据创建一个新的接口对象。如果类型是指针类型,它会创建一个指向该类型的指针,并将数据解析为该类型的对象。如果类型不是指针类型,它会创建一个该类型的对象,并将数据解析为该对象。Employee
结构体定义了一个名为Firstname
的字符串字段。
在main
函数中,它使用NewInterface
函数创建了一个Employee
对象,并将数据{"firstName": "John"}
解析为该对象。然后,它打印输出了该对象。
请注意,代码中的json:"firstname"
是用于指定结构体字段在JSON序列化和反序列化时的名称的标签。
英文:
// https://github.com/xiaojun207/go-base-utils/blob/master/utils/Clone.go
func NewInterface(typ reflect.Type, data []byte) interface{} {
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
dst := reflect.New(typ).Elem()
json.Unmarshal(data, dst.Addr().Interface())
return dst.Addr().Interface()
}else {
dst := reflect.New(typ).Elem()
json.Unmarshal(data, dst.Addr().Interface())
return dst.Interface()
}
}
type Employee struct {
Firstname string `json:"firstname"`
}
func main() {
data := "{\"firstName\": \"John\"}"
obj := NewInterface(reflect.TypeOf(Employee{}), []byte(data))
fmt.Println("Employee:", obj)
}
答案3
得分: 0
如果您完全不知道类型,可以将JSON字符串解组为interface{}。如果您需要处理解组后的数据,可以将其转换为所需的类型。
这里有一个示例:
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上进行测试。
英文:
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:
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)
}
You can check it on the Go Playground.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论