我想编写一个函数,该函数接收 几种 类型的结构并从JSON解组。为此,我有另一组带有预定义签名的函数,这些函数返回struct实例,但是由于每个函数都返回不同类型的struct,因此函数签名具有interface{}的返回类型。
interface{}
当我发送json.Unmarshal一个具体的结构时,它可以按照我的预期工作,但是当我发送相同的结构时,interface{}它将其转换为地图。
这是描述问题的简化示例代码:
package main import ( "encoding/json" "fmt" ) type Foo struct { Bar string `json:"bar"` } func getFoo() interface{} { return Foo{"bar"} } func main() { fooInterface := getFoo() fooStruct := Foo{"bar"} fmt.Println(fooInterface) //{bar} fmt.Println(fooStruct) //{bar} myJSON := `{"bar":"This is the new value of bar"}` jsonBytes := []byte(myJSON) err := json.Unmarshal(jsonBytes, &fooInterface ) if err != nil { fmt.Println(err) } fmt.Println(fooInterface) //map[bar:This is the new value of bar] err = json.Unmarshal(jsonBytes, &fooStruct) if err != nil { fmt.Println(err) } fmt.Println(fooStruct) //{This is the new value of bar} }
https://play.golang.org/p/tOO7Ki_i4c
我期望json.Unmarshal使用接口后面的具体结构来进行编组,但实际上并没有,只是将值的映射分配给所传递的接口。
为什么不使用具体的结构,有没有办法告诉它使用具体的结构类型而无需显式转换(我在设计时不知道显式类型)?
该encoding/json包不能奇迹般地猜测你想要的结果取消封送进去,除非你告诉它什么类型。
encoding/json
告诉要取消的内容的一种方法是将该类型的值传递给json.Unmarshal()函数。
json.Unmarshal()
不幸的是,没有其他办法。如果您传递interface{}类型的值,则json包实现可以自由选择其选择的类型,它将map[string]interface{}为JSON对象和[]interface{}JSON数组选择。记录在json.Unmarshal():
json
map[string]interface{}
[]interface{}
要将JSON解组为接口值,Unmarshal将其中之一存储在接口值中: bool, for JSON booleans float64, for JSON numbers string, for JSON strings []interface{}, for JSON arrays map[string]interface{}, for JSON objects nil for JSON null
要将JSON解组为接口值,Unmarshal将其中之一存储在接口值中:
bool, for JSON booleans float64, for JSON numbers string, for JSON strings []interface{}, for JSON arrays map[string]interface{}, for JSON objects nil for JSON null
如果您事先知道类型,请创建该类型的值,然后传递该值以进行编组。是否interface{}事先将其存储在变量中无关紧要;如果传递的值适合解组,则将使用它。请注意,传递的值将被包装为,interface{}如果尚未包含,则为,因为这是的参数类型json.Unmarshal()。
代码失败的原因是因为您传递了一个*interface{}包装非指针Foo值的type 值。由于json包不能使用它,因此它将创建一个新的选择值(地图)。
*interface{}
Foo
相反,您应该在中包装一个*Foo值interface{},然后传递该值:
*Foo
func getFoo() interface{} { return &Foo{"bar"} } func main() { fooInterface := getFoo() myJSON := `{"bar":"This is the new value of bar"}` jsonBytes := []byte(myJSON) err := json.Unmarshal(jsonBytes, fooInterface) if err != nil { fmt.Println(err) } fmt.Printf("%T %+v", fooInterface, fooInterface) }
结果是(在Go Playground上尝试):
*main.Foo &{Bar:This is the new value of bar}