嵌入式结构的多态 JSON 解组

Posted

技术标签:

【中文标题】嵌入式结构的多态 JSON 解组【英文标题】:Polymorphic JSON unmarshalling of embedded structs 【发布时间】:2017-06-06 01:34:39 【问题描述】:

这是一个例子(另见https://play.golang.org/p/or7z4Xc8tN):

package main

import (
    "encoding/json"
    "fmt"
)

type A struct 
    X string
    Y int


type B struct 
    A
    Y string 


func main() 
    data := []byte(`"X": "me", "Y": "hi"`)
    b := &B
    json.Unmarshal(data, b)
    fmt.Println(b)
    fmt.Println(b.A)

    b = &B
    data = []byte(`"X": "me", "Y": 123`)
    json.Unmarshal(data, b)
    fmt.Println(b)
    fmt.Println(b.A)

哪些输出:

&me 0 hi
me 0
&me 0 
me 0

有没有办法将字段 Y 多态地解组为 int 或字符串?或者甚至因为 B.Y 已定义而完全解组为 A.Y?

我知道有些人可能会建议使用 json.Unmarshall(data, &b.A) 之类的东西来解组,但我不知道我是否可以将它融入我当前的设计中。

【问题讨论】:

也许可以帮助***.com/questions/32428797/… 【参考方案1】:

Go 唯一的多态性是接口。嵌入不提供多态性。

如果您尝试在无法假设其中一个字段将是什么类型的情况下解组 JSON,则可以使用类型为 interface 的字段以及类型断言、fmt.Sprint 或反射。你应该使用哪个取决于特定的用例——一旦你得到了价值,你将如何处理它?在某些时候,您必须关心它是 int 还是 string,这将决定您如何处理该值。

【讨论】:

【参考方案2】:

正如 Adrian 所指出的,Go 不支持通过结构嵌入实现多态性。 interface 是保存任何类型的 golang 变量的唯一方法。但是,在您的情况下,您可以实现自定义 Unmarshaler 以使用 json.Numberinterface 将 JSON 流解码为结构。下面是使用json.Number 的实现。对于更通用的interface 版本,您可以按照 Adrian 的建议实现它。

func (b *B) UnmarshalJSON(js []byte) error 
    //First: decode stream to anonymous struct
    v := struct 
        X string
        Y json.Number
    

    err := json.Unmarshal(js, &v)
    if err != nil 
        return err
    

    //Depends on the v.Y value, choose the holder variable
    //If it's convertible to number, assign to A.Y
    //otherwise, assign it to b.Y
    b.X = v.X
    if fv, err := v.Y.Float64(); err == nil 
        b.A.Y = int(fv)
     else 
        b.Y = v.Y.String()
    

    return nil

工作示例可以在 The Go Playground 中找到。

【讨论】:

正如所写,else 永远不会被执行。调用 err := json.Unmarshal(js, &v) 后的返回 err 导致当数据内容不是数字(例如,“hi”)时不会发生 if/else。有了它,else (b.Y = v.Y.String()) 永远不会发生。此外,不会发生 b.X 的分配。在操场示例中,因此输出中缺少“我”。尽管如此,这个例子还是很有帮助的,所以感谢@putu。

以上是关于嵌入式结构的多态 JSON 解组的主要内容,如果未能解决你的问题,请参考以下文章

MarshallingException:无法解组结果参考

当 JSON 字段键是日期时,如何将 JSON 对象解组为 Golang 结构?

如何解组 JSON?

GOLANG 解组动态 JSON

在不知道结构的情况下解组嵌套的 json

C++基础——C++面向对象之重载与多态基础总结(函数重载运算符重载多态的使用)