英文:
How to make json.Unmarshal deal with interface{} correctly which contains an struct?
问题
你可以尝试将Data()
函数返回一个指向data
字段的指针,然后在SetData()
函数中将新数据解析为相应的类型,并将其赋值给data
字段。这样,你就可以在Data()
函数中返回data
字段的指针,而不必修改其他代码。
以下是修改后的代码示例:
type IDataContainer interface {
Data() interface{}
SetData(newData interface{})
}
type DataA struct {
Name string `json:"name"`
}
type StructA struct {
data *DataA
}
func (a *StructA) Data() interface{} {
return a.data
}
func (a *StructA) SetData(newData interface{}) {
a.data = newData.(*DataA)
}
type DataB struct {
Age int `json:"age"`
}
type StructB struct {
data *DataB
}
func (b *StructB) Data() interface{} {
return b.data
}
func (b *StructB) SetData(newData interface{}) {
b.data = newData.(*DataB)
}
func main() {
jsonDatas := [][]byte{[]byte(`{"name":"NEW"}`), []byte(`{"age":30}`)}
dataContainers := []IDataContainer{&StructA{}, &StructB{}}
for i, jsonData := range jsonDatas {
dataContainer := dataContainers[i]
data := dataContainer.Data()
json.Unmarshal(jsonData, data)
}
fmt.Println(dataContainers[0], dataContainers[1])
}
在修改后的代码中,data
字段被定义为指针类型,并且Data()
函数返回data
字段的指针。在SetData()
函数中,我们将新数据解析为相应的类型,并将其赋值给data
字段的指针。
这样,你就可以在Data()
函数中返回data
字段的指针,而不必修改其他代码。同时,json.Unmarshal()
函数也能正确地识别并解析数据类型。
英文:
type IDataContainer interface {
Data() interface{}
SetData(newData interface{})
}
type DataA struct {
Name string `json:"name"`
}
type StructA struct {
data DataA
}
func (a *StructA) Data() interface{} {
return a.data
}
func (a *StructA) SetData(newData interface{}) {
a.data = newData.(DataA)
}
type DataB struct {
Age int `json:"age"`
}
type StructB struct {
data DataB
}
func (b *StructB) Data() interface{} {
return b.data
}
func (b *StructB) SetData(newData interface{}) {
b.data = newData.(DataB)
}
func main() {
jsonDatas := [][]byte{[]byte(`{"name":"NEW"}`), []byte(`{"age":30}`)}
dataContainers := []IDataContainer{&StructA{}, &StructB{}}
for i, jsonData := range jsonDatas {
dataContainer := dataContainers[i]
data := dataContainer.Data()
// json.Unmarshal(jsonData, data) //Not working, data is not a pointer.
json.Unmarshal(jsonData, &data)
// dataContainer.SetData(data) // Not working, type of data becomes map[string]interface{}
}
}
The code may be a little strange because I removed irrelevant code of StructA and StructB.
There are many structs like StructA and StructB, such as StructC, StructD,StructE and so on...
They have many different functions to do different things,and they all implement the interface IDataContainer.
There are many "objects" or "instances" of them, and I have a dictionary to record them.
var dic map[string]IDataContainer = map[string]IDataContainer{...}
Users post key and json data, and I pick the IDataContainer by the key to receive the data.
Because I can't make the struct of the field "data" fixed and same,I have to use interface{} to hold the data that returned by Data().
I know that interface in golang is pointer acutally, but json.Unmarshal doesn't treat interface as pointer.
If I use "&data" as the parameter, json.Unmarshal treat it as map[string]interface{}.
I tried the code below:
type IDataContainer interface {
Data() interface{}
SetData(newData interface{})
}
type DataA struct {
Name string `json:"name"`
}
type StructA struct {
data DataA
}
func (a *StructA) Data() interface{} {
return &a.data
}
func (a *StructA) SetData(newData interface{}) {
a.data = *newData.(*DataA)
}
type DataB struct {
Age int `json:"age"`
}
type StructB struct {
data DataB
}
func (b *StructB) Data() interface{} {
return &b.data
}
func (b *StructB) SetData(newData interface{}) {
b.data = *newData.(*DataB)
}
func main() {
jsonDatas := [][]byte{[]byte(`{"name":"NEW"}`), []byte(`{"age":30}`)}
dataContainers := []IDataContainer{&StructA{}, &StructB{}}
for i, jsonData := range jsonDatas {
dataContainer := dataContainers[i]
data := dataContainer.Data()
json.Unmarshal(jsonData, &data)
// dataContainer.SetData(data) // Not be needed,because the data is modified by json.Unmarshal already.
}
fmt.Println(dataContainers[0], dataContainers[1]) // Works! but...
}
The Data() function returns the pointer of data,and json.Unmarshal detect the type conrrectly.
Althogh it works, I don't want Data() to return the pointer of the field data because of some complex reason.
How to deal with this problem?
答案1
得分: 1
好的,以下是翻译好的内容:
好的。
我使用反射(reflect)自己解决了这个问题,但是代码不够简洁。
老实说,我并不完全理解它为什么能工作。
我使用反射创建了一个临时变量,并将其类型设置为与数据的具体类型相同,然后使用它进行解组(unmarshal)。
func main() {
jsonDatas := [][]byte{[]byte(`{"name":"NEW"}`), []byte(`{"age":30}`)}
dataContainers := []IDataContainer{&StructA{}, &StructB{}}
for i, jsonData := range jsonDatas {
dataContainer := dataContainers[i]
data := dataContainer.Data()
t := reflect.New(reflect.TypeOf(data)).Interface()
json.Unmarshal(jsonData, &t)
dataContainer.SetData(reflect.ValueOf(t).Elem().Interface())
}
fmt.Println(dataContainers[0], dataContainers[1])
}
英文:
Ok.
I solve the problem by myself using reflect, but it is not concise.
To be honest, I can't understand completely why it works.
I make a temporary variable using reflect,and make its type same as the
concrete type of data, and unmarshal with it.
func main() {
jsonDatas := [][]byte{[]byte(`{"name":"NEW"}`), []byte(`{"age":30}`)}
dataContainers := []IDataContainer{&StructA{}, &StructB{}}
for i, jsonData := range jsonDatas {
dataContainer := dataContainers[i]
data := dataContainer.Data()
t := reflect.New(reflect.TypeOf(data)).Interface()
json.Unmarshal(jsonData, &t)
dataContainer.SetData(reflect.ValueOf(t).Elem().Interface())
}
fmt.Println(dataContainers[0], dataContainers[1])
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论