Buz*_*zzy 12 json struct go unmarshalling
我想编写一个函数来接收几种类型的结构并从 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}
}
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/tOO7Ki_i4c
我希望 json.Unmarshal 使用接口后面的具体结构进行解组,但它没有,只是将值的映射分配给传递的接口。
为什么它不使用具体结构,有没有办法告诉它使用具体结构类型而不进行显式转换(我在设计时不知道显式类型)?
encoding/json
除非您告诉它,否则该包无法神奇地猜测您希望将结果解组为哪种类型。
告诉解组到什么的一种方法是将该类型的值传递给json.Unmarshal()
函数。
不幸的是,没有其他办法。如果你传递一个interface{}
类型的值,json
包实现可以自由选择它所选择的类型,它会map[string]interface{}
为 JSON 对象和[]interface{}
JSON 数组选择。这是记录在json.Unmarshal()
:
要将 JSON 解组为接口值,Unmarshal 将其中之一存储在接口值中:
Run Code Online (Sandbox Code Playgroud)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{}
if not already 的类型中,因为这是 的参数类型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)
}
Run Code Online (Sandbox Code Playgroud)
这导致(在Go Playground上尝试):
*main.Foo &{Bar:This is the new value of bar}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6132 次 |
最近记录: |