Reputation: 1060
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?
Upvotes: 0
Views: 75
Reputation: 1060
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])
}
Upvotes: 1