登录
首页 >  Golang >  Go问答

如何告诉 json.Unmarshal 使用结构而不是接口

来源:Golang技术栈

时间:2023-04-04 17:16:19 382浏览 收藏

积累知识,胜过积蓄金银!毕竟在##column_title##开发的过程中,会遇到各种各样的问题,往往都是一些细节知识点还没有掌握好而导致的,因此基础知识点的积累是很重要的。下面本文《如何告诉 json.Unmarshal 使用结构而不是接口》,就带大家讲解一下golang知识点,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~

问题内容

我想编写一个函数来接收 几种 类型的结构并从 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 使用接口后面的具体结构进行解组,但它没有,只是将值映射分配给传递的接口。

为什么它不使用具体结构,有没有办法告诉它使用具体结构类型而不显式转换(我在设计时不知道显式类型)?

正确答案

除非您告诉它,否则该encoding/json包无法神奇地猜测您希望将结果解组为哪种类型。

告诉解组到什么的一种方法是将该类型的值传递给json.Unmarshal()函数。

不幸的是,没有其他办法。如果你传递一个interface{}类型的值,json包实现可以自由选择它选择的类型,它将map[string]interface{}为 JSON 对象和[]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}

以上就是《如何告诉 json.Unmarshal 使用结构而不是接口》的详细内容,更多关于golang的资料请关注golang学习网公众号!

声明:本文转载于:Golang技术栈 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>