我想编写一个函数来接收几种类型的结构,并从JSON中解组它们。为此,我有另一组具有预定义签名的函数,它返回结构实例,但由于每个函数返回不同类型的结构,因此函数签名具有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能够使用接口后面的具体结构进行解组,但它并没有将值映射分配给传递的接口。
为什么它没有使用具体的结构,有没有办法告诉它使用具体的结构类型而没有显式的转换(我不知道设计时的显式类型)?
答案 0 :(得分:4)
encoding/json
包不能神奇地猜出你想要将结果解组到哪种类型,除非你告诉它。
告诉unmarsal进入的一种方法是将该类型的值传递给json.Unmarshal()
函数。
不幸的是,别无他法。如果传递interface{}
类型的值,则json
包实现可以自由选择其选择的类型,并且它将为JSON对象选择map[string]interface{}
,并[]interface{}
用于JSON数组。这在json.Unmarshal()
:
要将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
类型的值。由于json
包不能使用它,因此会创建一个新的选择值(地图)。
相反,您应该在*Foo
中包含interface{}
值,然后传递:
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}